uva1625 Color Length

题意不说了

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

定义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
    }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值