题意:
每次给你两个串,第一个是正确的串,第二个是输入的串,你有添加,修改,删除三种操作,问你需要多少次操作才能让第二个串变成第一个串,根据操作次数输出不同的语句,>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
*/