您的位置:首页 > 其它

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  动态规划 算法