Description
Input
Output
对于每组数据,输出真实事件序列的最长可能长度。
Sample Input
1 9 1 4 2 6 3 8 5 9 1 6 2 7 6 3 5 1
Sample Output
3分析:求最长公共上升子序列的模板题。设题目给出a[],b[]两个序列。f[j]表示b序列到j的时候,与a[??]序列构成最长公共上升子序列的最优解。其中a[??]序列,从1到n枚举过来。
如果某一个时刻a[i]==b[j],那么显然,我们就应该在0到j-1中,找一个f值最大的来更新最优解。这和求上升子序列是思想是一样的。另外,在枚举b[j]的时候,我们顺便保存一下小于a[i]的f值最大的b[j],这样在更新的时候,我们就可以做到O(1)的复杂度,从而将整个算法的复杂度保证在O(nm)
想不通的时候就手动模拟一下,世界自然就和平了。。。。。
注意这里与n,m的相对大小没有关系,结果都一样。
ac代码:
#include <stdio.h> #include <string.h> #include <algorithm> using namespace std; int a[1005],b[1005],dp[1005],n,m; int LICS()//作为模板直接使用 { int i,j,MAX; memset(dp,0,sizeof(dp)); for(i = 1; i<=n; i++) { MAX = 0; for(j = 1; j<=m; j++) { if(a[i]>b[j] && MAX<dp[j]) MAX = dp[j]; if(a[i]==b[j]) dp[j] = MAX+1; } } MAX = 0; for(i = 1; i<=m; i++) if(MAX<dp[i]) MAX = dp[i]; return MAX; } int main() { int T,i; scanf("%d",&T); while(T--) { scanf("%d",&n); for(i = 1;i<=n;i++) scanf("%d",&a[i]); scanf("%d",&m); for(i = 1;i<=m;i++) scanf("%d",&b[i]); printf("%d\n",LICS()); } return 0; }