题目:click
题意:利用该操作,问最小的操作次数使得s变为t,如果不可能则-1.
思路来源:https://www.bilibili.com/video/BV13T4y1J73t?p=6
记录一下这个dp,切入点在最长的公共子序列,答案min,肯定需要公共子序列max,n-max(公共子序列的长度)即答案,我们只需要改变不是最长公共子序列的字符,但是注意就只能向前移动,
所以每次匹配的时候,在者之后的a-z个数s序列一定要大于等于t的,不然无法完成,因为s序列在此之前的非最长公共子序列的字符只能往前面移动,后面的不能匹配到。
#include<cmath>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cstdlib>
#include<istream>
#include<vector>
#include<stack>
#include<set>
#include<map>
#include<algorithm>
#include<queue>
#define inf 0x3f3f3f3f
#define llinf 0x3f3f3f3f3f3f3f3f
#define MAX_len 200005*4
using namespace std;
typedef long long ll;
char s[2010],t[2010];
int dp[2010][2010];
int num1[2010][30];
int num2[2010][30];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n,i,j;
scanf("%d",&n);
scanf("%s",s+1);
scanf("%s",t+1);
if(strcmp(s+1,t+1)==0)
{
printf("0\n");
continue;
}
memset(num1[n+1],0,sizeof(num1[n+1]));
memset(num2[n+1],0,sizeof(num2[n+1]));
for(i=n;i>=1;i--)
{
for(j=0;j<26;j++)
{
num1[i][j]=num1[i+1][j];
num2[i][j]=num2[i+1][j];
}
num1[i][s[i]-'a']++;
num2[i][t[i]-'a']++;
}
bool flag=true;
for(i=0;i<26;i++)
{
if(num1[1][i]!=num2[1][i])
{
flag=false;
break;
}
}
if(!flag)
{
printf("-1\n");
continue;
}
dp[0][0]=0;
for(i=0;i<=n;i++)
{
for(j=0;j<=n;j++)
{
if(i)
dp[i][j]=dp[i-1][j];
if(j)
dp[i][j]=max(dp[i][j],dp[i][j-1]);
if(i&&j&&s[i]==t[j])
{
flag=true;
for(int k=0;k<26;k++)
{
if(num1[i+1][k]>=num2[j+1][k])
continue;
else
{
flag=false;
break;
}
}
if(flag)
{
dp[i][j]=max(dp[i][j],dp[i-1][j-1]+1);
}
}
}
}
printf("%d\n",n-dp[n][n]);
}
return 0;
}