您的位置:首页 > 其它

Codeforces 682D Alyona and Strings(DP)

2016-07-12 09:16 155 查看
题目大概说给两个字符串s和t,然后要求一个包含k个字符串的序列,而这个序列是两个字符串的公共子序列,问这个序列包含的字符串的总长最多是多少。

如果用DP解,考虑到问题的规模,自然这么表示状态:

dp[i][j][k]表示s[0...i]与t[0...j]包含k个字符串的公共子序列的最大总长

想怎么转移时,我发现这样表示状态不好转移,还得加一维:

dp[i][j][k][0]表示s[0...i]与t[0...j]包含k个字符串的公共子序列的最大总长,且s[i]和t[j]不属于序列第k个字符串

dp[i][j][k][1]表示s[0...i]与t[0...j]包含k个字符串的公共子序列的最大总长,且s[i]和t[j]属于序列第k个字符串

转移的话:

dp[i][j][k][1]能转移仅s[i]=t[j],可以通过在s[0...i-1]和t[0...j-1]的后面作为新加的序列字符串转移,即d[i-1][j-1][k-1]+1;也可以不作为新加的序列字符串,与前面的拼接转移,不过仅当s[i-1]=t[j-1],即dp[i-1][j-1][k]+1;

dp[i][j][k][0]就是s[i]、t[j]忽略的情况,从dp[i-1][j][k]、dp[i][j-1][k]和dp[i][j][k]转移

转移感觉很麻烦,写着写着调着调着,终于过了样例,然后直接提交——居然就AC了?简直不敢相信。。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int d[1111][1111][11][2];
int main(){
int n,m,K;
char s[1111]={0},t[1111]={0};
scanf("%d%d%d",&n,&m,&K);
for(int i=0; i<n; ++i){
scanf(" %c",&s[i]);
}
for(int i=0; i<m; ++i){
scanf(" %c",&t[i]);
}
memset(d,0,sizeof(d));
if(s[0]==t[0]) d[0][0][1][1]=1;
for(int i=0; i<n; ++i){
for(int j=0; j<m; ++j){
if(i==0 && j==0) continue;
for(int k=1; k<=K; ++k){
if(i==0){
if(s[i]==t[j]){
d[i][j][1][1]=1;
}
d[i][j][1][0]=max(d[i][j-1][1][0],d[i][j-1][1][1]);
}else if(j==0){
if(s[i]==t[j]){
d[i][j][1][1]=1;
}
d[i][j][1][0]=max(d[i-1][j][1][0],d[i-1][j][1][1]);
}else{
if(s[i]==t[j]){
d[i][j][k][1]=max(d[i-1][j-1][k-1][0],d[i-1][j-1][k-1][1])+1;
if(s[i-1]==t[j-1]) d[i][j][k][1]=max(d[i][j][k][1],d[i-1][j-1][k][1]+1);
}
d[i][j][k][0]=max(d[i-1][j][k][0],d[i][j-1][k][0]);
d[i][j][k][0]=max(d[i][j][k][0],d[i][j-1][k][1]);
d[i][j][k][0]=max(d[i][j][k][0],d[i-1][j][k][1]);
d[i][j][k][0]=max(d[i][j][k][0],d[i-1][j-1][k][0]);
if(s[i-1]==t[j-1]) d[i][j][k][0]=max(d[i][j][k][0],d[i-1][j-1][k][1]);
}
}
}
}
printf("%d",max(d[n-1][m-1][K][0],d[n-1][m-1][K][1]));
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: