我们可以以北岸城市为关键字将友好城市排序。
这样就将问题转换成,求南岸最长上升子序列LIS。
顺便提一句LIS的几种算法。
首先是O(n^2),
设dp[i]表示以i为结尾的最长上升子序列的长度,则状态转移方程为:
dp[i] = max{dp[j]+1}, 1<=j<i,a[j]<a[i].
其次是O(n log n),
这里只写一个简易而高效的算法,类似于贪心,
建立一个栈,初始为空,栈顶元素top=0,
每遇到一个新元素k,比较k与top的大小,
若k<top,则在栈中二分查找到第一个比k大的数,并将其替换为k;
若k>top,k入栈。
最后栈中元素个数即为所求。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 struct fx{ 6 int u,v; 7 }c[5001]; 8 bool cmp(fx a,fx b){ 9 return a.u<b.u; 10 } 11 int zh[5001],f[5001]; 12 int find(int); 13 int tail; 14 int main(){ 15 int n,top,tmp; 16 top=tail=0; 17 scanf("%d",&n); 18 for (int i=1;i<=n;i++) 19 scanf("%d %d",&c[i].u,&c[i].v); 20 sort(c+1,c+n+1,cmp); 21 for (int i=1;i<=n;i++){ 22 if (c[i].v>top){ 23 zh[++tail]=c[i].v; 24 top=c[i].v; 25 } 26 else 27 zh[upper_bound(zh+1,zh+tail+1,c[i].v)-zh]=c[i].v; 28 } 29 printf("%d",tail); 30 return 0; 31 }