Gym 102536 A The Slowden Files —— DP

This way

题意:

每次给你两个串,第一个是正确的串,第二个是输入的串,你有添加,修改,删除三种操作,问你需要多少次操作才能让第二个串变成第一个串,根据操作次数输出不同的语句,>3次一视同仁

题解:

虽然不是什么难的题目,但是它让我wa了好几发,还是写一下回顾一下。
很容易想到,既然只有三种操作,并且最多操作次数不超过3次,那么可以设
dp[i][j][k]表示第一个串到第i个位置的时候,第二个串在之前已经有了j次添加,k次删除操作的时候,最少的修改次数。
那么第i个位置对应的第二个串的位置就是i-j+k,首先如果这两个位置相同,那么就直接转移到dp[i+1][j][k]上即可。
如果不相同,此时有两种情况,第一种是第二个串确实存在i-j+k这个位置,那么有三种操作:修改,添加和删除,对于删除操作,我们要看第二个串后面哪个位置和第一个串的i位相同。
第二种就是第二个串不存在i-j+k这个点,有可能是第二个串本来就太短了,也有可能是前面删掉了k个导致的,此时只能增加一个点。
最后计算答案的时候要注意,当l1-i+j!=l2的时候,也就是长度有出入的时候呢,需要加上相差的长度。
就是上面我特别提到的点,一发一发wa过去,真是扑街。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int dp[N][4][4];
string s1,s2;
int main()
{
    cin.tie(0);
    ios::sync_with_stdio(false);
    int t;
    cin>>t;
    cin.get();
    while(t--){
        getline(cin,s1);
        //cout<<s1<<endl;
        //cin.get();
        getline(cin,s2);
        //cout<<s2<<endl;
        int l1=s1.length(),l2=s2.length();

        for(int i=0;i<=l1;i++)
            for(int j=0;j<=3;j++)
                for(int k=0;k<=3;k++)
                    dp[i][j][k]=-1;
        dp[0][0][0]=0;
        for(int i=0;i<l1;i++){
            for(int j=0;j<=3;j++){
                for(int k=0;k<=3-j;k++){
                    if(i-j+k<0||dp[i][j][k]==-1)
                        continue;
                    if(i-j+k<l2&&s1[i]==s2[i-j+k])
                        dp[i+1][j][k]=dp[i+1][j][k]==-1?dp[i][j][k]:min(dp[i+1][j][k],dp[i][j][k]);

                    else{
                        if(i-j+k<l2)
                            dp[i+1][j][k]=dp[i+1][j][k]==-1?dp[i][j][k]+1:min(dp[i+1][j][k],dp[i][j][k]+1);
                        if(j<3)
                            dp[i+1][j+1][k]=dp[i+1][j+1][k]==-1?dp[i][j][k]:min(dp[i+1][j+1][k],dp[i][j][k]);
                        if(k<3&&i-j+k+1<l2&&s1[i]==s2[i-j+k+1])
                            dp[i+1][j][k+1]=dp[i+1][j][k+1]==-1?dp[i][j][k]:min(dp[i+1][j][k+1],dp[i][j][k]);
                        if(k<2&&i-j+k+2<l2&&s1[i]==s2[i-j+k+2])
                            dp[i+1][j][k+2]=dp[i+1][j][k+2]==-1?dp[i][j][k]:min(dp[i+1][j][k+2],dp[i][j][k]);
                        if(k<1&&i-j+k+3<l2&&s1[i]==s2[i-j+k+3])
                            dp[i+1][j][k+3]=dp[i+1][j][k+3]==-1?dp[i][j][k]:min(dp[i+1][j][k+3],dp[i][j][k]);
                    }
                }
            }
        }
        int mi=1e9;
        for(int i=0;i<=3;i++){
            for(int j=0;j<=3-i;j++){
                if(~dp[l1][i][j]){
                    int res=abs(l2+i-j-l1);
                    mi=min(mi,dp[l1][i][j]+i+j+res);
                }
            }
        }
        if(mi==0)
            cout<<"You're logged in!"<<endl;
        else if(mi==1)
            cout<<"You almost got it. You're wrong in just one spot."<<endl;
        else if(mi==2)
            cout<<"You almost got it, but you're wrong in two spots."<<endl;
        else if(mi==3)
            cout<<"You're wrong in three spots."<<endl;
        else
            cout<<"What you entered is too different from the real password."<<endl;
    }
    return 0;
}
/*
1
123456
61234556


*/
发布了584 篇原创文章 · 获赞 33 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/tianyizhicheng/article/details/104807152
今日推荐