dp学习笔记3
今天学了求最长递增子序列的O(n*log(n))算法。。。
View Code
1 /* 2 【问题描述】 3 PALMIA国家被一条河流分成南北两岸,南北两岸上各有N个村庄。北岸的每一个村庄有一个唯一的朋友在南岸,且他们的朋友村庄彼此不同。 4 每一对朋友村庄想要一条船来连接他们,他们向政府提出申请以获得批准。由于河面上常常有雾,政府决定禁止船只航线相交(如果相交,则很可能导致碰船)。 5 你的任务是编写一个程序,帮助政府官员决定批准哪些船只航线,使得不相交的航线数目最大。 6 */ 7 /* 8 测试样例: 9 30 4 10 7 11 22 4 12 2 6 13 10 3 14 15 12 15 9 8 16 17 17 17 4 2 18 正确输出: 19 4 20 */ 21 /* 22 于任意两条航线如果满足Ci<Cj 且Di<Dj 则两条航线不相交。 23 这样的话要想在一个序列里让所有的航线都不相交那比然满足,C1<C2<C3…Cans且D1<D2<D3…<Dans , 24 也就是将C排序后求出最长的满足这个条件的序列的长度就是解 25 */ 26 ///以下是n*log(n)的做法。。。 27 #include<iostream> 28 #include<algorithm> 29 const int N=5007; 30 using namespace std; 31 32 struct Node{ 33 int x,y; 34 }node[N]; 35 int dp[N]; 36 37 int cmp(Node &a,Node &b){ 38 if(a.x != b.x) 39 return a.x<b.x; 40 return a.y<b.y; 41 } 42 43 int Search(int dp[],int len,int num){ 44 int low=1,high=len; 45 while(low<=high){ 46 int mid=(low+high)/2; 47 if(num==dp[mid])return mid; 48 else if(num<dp[mid])high=mid-1; 49 else low=mid+1; 50 } 51 return low; 52 } 53 54 int main(){ 55 int lx,ly; 56 while(~scanf("%d%d",&lx,&ly)){ 57 int n; 58 scanf("%d",&n); 59 for(int i=1;i<=n;i++){ 60 scanf("%d%d",&node[i].x,&node[i].y); 61 } 62 sort(node+1,node+n+1,cmp); 63 dp[0]=-1,dp[1]=node[1].y; 64 int len=1; 65 //n*log(n)算法求最长非下降子序列 66 for(int i=2;i<=n;i++){ 67 int pos=Search(dp,len,node[i].y); 68 dp[pos]=node[i].y; 69 if(pos>len)len++; 70 } 71 printf("%d\n",len); 72 } 73 return 0; 74 }