您的位置:首页 > 其它

uva1625 Color Length

2017-07-18 08:52 211 查看
题意不说了

题解:(还是去网上搜了题解。。。)

定义dp[i][j]为第1个序列被取走了i个字符,第二个序列被取走了j个字符

定义c[i][j]为两个字符串分别被取走i,j个字符后还有多少已经开始但仍未结束的字符,这个是可以预处理出来的

而对于新序列来说,每增加一个字符,它的ans就会增加c

于是dp方程式就是:dp[i][j]=min(dp[i-1][j]+c[i-1][j],dp[i][j-1]+c[i][j-1])

实在是巧妙,表示膜拜,有兴趣可以直接去看原文:http://www.cnblogs.com/AOQNRMGYXLMV/p/4006498.html

代码的实现也是非常巧,还用了滚动数组优化空间:

code:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>

const int MAXN=5005;
const int inf=0x3f3f3f3f;
using namespace std;
char A[MAXN],B[MAXN];
int sA[30],sB[30];//这里储存的是每个字符的开始位置
int eA[30],eB[30];//这里储存的是每个字符的结束位置
int dp[2][MAXN];
int c[2][MAXN];

int main()
{
int T; scanf("%d",&T);
while(T--)
{
scanf("%s%s",A+1,B+1);
int lenA=strlen(A+1);
int lenB=strlen(B+1);
for(int i=1;i<=lenA;i++) A[i]-='A';
for(int i=1;i<=lenB;i++) B[i]-='A';
memset(sA,0x3f,sizeof sA);
memset(sB,0x3f,sizeof sB);
memset(eA,0,sizeof eA);
memset(eB,0,sizeof eB);//之前因为这里没清Wa了
for(int i=1;i<=lenA;i++)
{
sA[A[i]]=min(sA[A[i]],i);
eA[A[i]]=i;
}
for(int i=1;i<=lenB;i++)
{
sB[B[i]]=min(sB[B[i]],i);
eB[B[i]]=i;
}
memset(dp,0,sizeof dp);
memset(c,0,sizeof c); int t=0;
for(int i=0;i<=lenA;i++)
{
for(int j=0;j<=lenB;j++)
{
if(!i&&!j) continue;
int v1=inf,v2=inf;
if(i) v1=dp[t^1][j]+c[t^1][j];
if(j) v2=dp[t][j-1]+c[t][j-1];
dp[t][j]=min(v1,v2);//这里先做dp再更新c的原因是计算字符串长度时,长度要-1
if(i)
{
c[t][j]=c[t^1][j];
if(sA[A[i]]==i&&sB[A[i]]>j) c[t][j]++;
if(eA[A[i]]==i&&eB[A[i]]<=j) c[t][j]--;
}
else if(j)//这个else if可以保证c[0][j]只被更新一次,用dp的观点来看,相当于赋初值
{
c[t][j]=c[t][j-1];
if(sB[B[j]]==j&&sA[B[j]]>i) c[t][j]++;
if(eB[B[j]]==j&&eA[B[j]]<=i) c[t][j]--;
}
}
t^=1;
}
printf("%d\n",dp[t^1][lenB]);//不是t的原因是循环结束时t^=1
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: