JZOJ 4762 千帆渡(动态规划)
2016-12-15 16:45
459 查看
题目大意
给出长度各为n和m的序列a和b,求它们的最长公共上升子序列并输出任一方案。n,m<=5000
时间限制 1s
空间限制 256M
解题思路
f[i][j]表示a中1~i中的某一位和b中第j位结尾得出的序列长度。1、a[i]==b[j]:f[i][j]=max(f[i-1][k]),k<j && b[k]<b[j];
2、a[i]!=b[j]:f[i][j]=f[i-1][j];
来看第一条,把转移条件替换一下得出->k<j && b[k]<a[i],
所以我们在DP的时候,在j的那重循环维护满足上述条件的max(f[i-1][j]);
这样转移状态的时间复杂度就是O(1),总的时间复杂度O(nm);
如何输出方案就不再赘述了。
附上代码
#include<cstdio> #include<cstring> #include<algorithm> #define maxn 5006 #define fr(i,a,b) for(i=a;i<=b;i++) using namespace std; int i,j,n,m,x,y,tot,ans,a[maxn],b[maxn]; int sum[maxn],sans[maxn],f[maxn][maxn]; int main() { scanf("%d",&n); fr(i,1,n) scanf("%d",&a[i]); scanf("%d",&m); fr(i,1,m) scanf("%d",&b[i]); fr(i,1,n) fr(j,1,m) { f[i][j]=f[i-1][j]; if (a[i]==b[j]) f[i][j]=max(f[i][j],sum[i-1]+1); if (b[j]<a[i]) sum[i-1]=max(sum[i-1],f[i-1][j]); ans=max(ans,f[i][j]); } printf("%d\n",ans); x=n,y=m,a[x+1]=1 << 30; while (ans) { bool kan=0; for(i=x;i;i--) { for(j=y;j;j--) if (a[i]==b[j] && a[i]<a[x+1] && f[i][j]==ans) { kan=1; break; } if (kan) break; } x=i-1,y=j-1; sans[++tot]=a[i],--ans; } for(i=tot;i;i--) printf("%d ",sans[i]); printf("\n"); return 0; }
相关文章推荐
- 书评:《算法之美( Algorithms to Live By )》
- 动易2006序列号破解算法公布
- C#递归算法之分而治之策略
- Ruby实现的矩阵连乘算法
- C#插入法排序算法实例分析
- C#算法之大牛生小牛的问题高效解决方法
- C#算法函数:获取一个字符串中的最大长度的数字
- 超大数据量存储常用数据库分表分库算法总结
- C#数据结构与算法揭秘二
- C#冒泡法排序算法实例分析
- 算法练习之从String.indexOf的模拟实现开始
- C#算法之关于大牛生小牛的问题
- C#实现的算24点游戏算法实例分析
- 经典排序算法之冒泡排序(Bubble sort)代码
- Android数据加密之异或加密算法的实现方法
- c语言实现的带通配符匹配算法
- 浅析STL中的常用算法
- 算法之排列算法与组合算法详解
- C++实现一维向量旋转算法
- Ruby实现的合并排序算法