UVa1625 Color Length


题目描述
传送门


参照刘汝佳书上的思路。一开始自己写了个记忆化搜索超时了,哪位高人能指点一下超时的原因…

//TLE!
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int l1,l2,b1[200],b2[200],e1[200],e2[200],d[5010][5010],cnt=0;
//d[i][j]表示s1,s2分别取了i,j个颜色,还需要的L值
char s1[20010],s2[20010];
int dp(int i,int j,int tot){//tot表示已经出现但未结束的颜色的总数
    if(i>l1||j>l2) return 100000000;
    if(d[i][j]>-1) return d[i][j];
    d[i][j]=tot;
    int t1=tot,t2=tot;
    if(i+1==b1[s1[i+1]]&&(b2[s1[i+1]]>j||b2[s1[i+1]]==-1)) t1++;
    if(i+1==e1[s1[i+1]]&&(e2[s1[i+1]]<=j||b2[s1[i+1]]==-1)) t1--;
    if(j+1==b2[s2[j+1]]&&(b1[s2[j+1]]>i||b1[s2[j+1]]==-1)) t2++;
    if(j+1==e2[s2[j+1]]&&(e1[s2[j+1]]<=i||b1[s2[j+1]]==-1)) t2--;//计算其他的tot
    return d[i][j]+=min(dp(i+1,j,t1),dp(i,j+1,t2));//转移
}
int main(){
    int t;
    cin>>t;
    while(t--){
        memset(b1,-1,sizeof(b1));
        memset(b2,-1,sizeof(b2));
        scanf("%s%s",s1+1,s2+1);
        l1=strlen(s1+1),l2=strlen(s2+1);
        for(int i=1;i<=l1;i++){//计算s1里每种颜色的开始和结束位置(b1表示开始的位置,e1表示结束的位置,下同)
            if(b1[s1[i]]==-1) b1[s1[i]]=i;
            e1[s1[i]]=i;
        }
        for(int i=1;i<=l2;i++){//计算s2里每种颜色的开始和结束位置
            if(b2[s2[i]]==-1) b2[s2[i]]=i;
            e2[s2[i]]=i;
        }
        memset(d,-1,sizeof(d));
        d[l1][l2]=0;
        printf("%d\n",dp(0,0,0));
    }
    return 0;
}

后来换成递推的就AC了

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int l1,l2,b1[200],b2[200],e1[200],e2[200],d[5010][5010],tot[5010][5010];
char s1[20010],s2[20010];
int main(){
    int t;
    cin>>t;
    while(t--){
        memset(b1,-1,sizeof(b1));
        memset(b2,-1,sizeof(b2));
        scanf("%s%s",s1+1,s2+1);
        l1=strlen(s1+1),l2=strlen(s2+1);
        for(int i=1;i<=l1;i++){
            if(b1[s1[i]]==-1) b1[s1[i]]=i;
            e1[s1[i]]=i;
        }
        for(int i=1;i<=l2;i++){
            if(b2[s2[i]]==-1) b2[s2[i]]=i;
            e2[s2[i]]=i;
        }
        for(int i=0;i<=l2+1;i++) d[l1+1][i]=1000000000;
        for(int i=0;i<=l1+1;i++) d[i][l2+1]=1000000000;
        d[l1][l2]=0;
        tot[0][0]=0;
        for(int i=0;i<=l1;i++){
            for(int j=0;j<=l2;j++){
                int t1=tot[i][j],t2=tot[i][j];
                if(i+1==b1[s1[i+1]]&&(b2[s1[i+1]]>j||b2[s1[i+1]]==-1)) t1++;
                if(i+1==e1[s1[i+1]]&&(e2[s1[i+1]]<=j||b2[s1[i+1]]==-1)) t1--;
                if(j+1==b2[s2[j+1]]&&(b1[s2[j+1]]>i||b1[s2[j+1]]==-1)) t2++;
                if(j+1==e2[s2[j+1]]&&(e1[s2[j+1]]<=i||b1[s2[j+1]]==-1)) t2--;
                tot[i+1][j]=t1;tot[i][j+1]=t2;
            }
        }
        for(int i=l1;i>=0;i--){
            for(int j=l2;j>=0;j--){
                if(i==l1&&j==l2) continue;
                d[i][j]=min(d[i+1][j],d[i][j+1])+tot[i][j];
            }
        }
        printf("%d\n",d[0][0]);
    }
    return 0;
}               
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值