CodeVS2185 最长公共上升子序列
来源:互联网 发布:gbk转utf8 java 编辑:程序博客网 时间:2024/06/10 17:02
题
http://codevs.cn/problem/2185/
题解
令f[i][j]表示不强制选择a[i]且强制选择b[j]的答案。
之所以这么设定,经过了一番考虑。如果你让f[i][j]表示a[i]和b[j]都不强制选,那么你无法确定答案所对应的结果中a[i]或者b[j]是否已经匹配,转移似乎就比较比较难想;如果让f[i][j]表示两者都强制选,那么二者不匹配时你就把答案设为负无穷,如果匹配,你要枚举前面哪两个匹配,这样时间复杂度太高。于是我们就让一个不强制选择,一个强制选择。就出来了状态转移方程:
当a[i]==b[j]时,f[i][j]=f[i-1][k],其中k小于j且满足b[k]<b[j]。当a[i]!=b[j]时,f[i][j]=f[i][j-1]。
那么框架出来了,枚举i、枚举j,当a[i]==b[j]时还要枚举k。这样的话时间复杂度为O(N^3)
怎么优化?头疼了半天,后来看了一篇题解就懂了。
我们暂且先不考虑i这一维,i定住不动,也就是a[i]不变,要计算所有的j∈[1,N]的f[i][j]。当a[i]==b[j]时,就要枚举f[i-1][k],需满足b[k]<b[j],而由于a[i]的不变,所有需要转移的b[j]的值也就是相等的,也就是说你之前枚举的所有k,在后来的转移中一定也会用到,所以我们每加入一个新的枚举对象(即当出现一个a[i]==b[j])时,就打擂台统计max,转移的时候,直接将max+1赋给f[i][j]就行了。
思想:这里的优化中,打擂台求最小其实没啥,最有用的一个思想就是把大的维度定住不动,只考虑低维度,这样就能把高维问题转化为低维问题,大大降低了思维复杂度。这貌似是所有DP优化中共用的思想吧?
ps:这道题如果规定匹配的区间,能否用单调队列做呢?
代码
#include <cstdio>#include <algorithm>#define maxn 3010using namespace std;int f[maxn][maxn], a[maxn], b[maxn], N;int main(){int i, j, maxx, ans=0;scanf("%d",&N);for(i=1;i<=N;i++)scanf("%d",a+i);for(i=1;i<=N;i++)scanf("%d",b+i);for(i=1;i<=N;i++){maxx=0;for(j=1;j<=N;j++){if(a[i]==b[j])f[i][j]=maxx+1;else f[i][j]=f[i-1][j];if(a[i]>b[j])maxx=max(maxx,f[i-1][j]);ans=max(ans,f[i][j]);}}printf("%d\n",ans);return 0;}
- CodeVS2185 最长公共上升子序列
- Codevs2185 最长公共上升子序列
- [CODEVS2185]最长公共上升子序列(dp)
- 线性DP codevs2185 最长公共上升子序列
- 最长公共上升子序列
- 最长公共上升子序列
- 最长上升公共子序列
- 最长公共上升子序列
- 最长公共上升子序列
- 最长公共上升子序列
- 最长公共上升子序列
- 最长公共上升子序列
- 最长公共上升子序列
- 最长公共上升子序列
- 最长公共子上升序列
- 最长公共上升子序列
- 最长公共上升子序列
- 最长上升子序列、最长公共上升子序列
- 纯洁
- JS原生addClass、removeClass实现
- Xshell连接Ubuntu时SSH服务器拒绝了密码问题
- App路由简记(一)
- (提高篇)第一讲 项目 简单的函数运用(一)
- CodeVS2185 最长公共上升子序列
- OKHttp源码分析(一)
- Linux下静态IP的配置
- Hadoop HA笔记
- delphi xe连接oracle心得(备忘)纯原创,一个字一个字打的
- 【自考总结篇——2016年10月】
- http协议
- 51nod 1068【简单博弈】
- bootstrap小笔记 各种组件(轮播图/模态框/菜单监听....)