题解:盾盾的打字机
题目
题目描述
盾盾有一个非常有意思的打字机,现在盾哥要用这台打字机来打出一段文章。
由于有了上次的经验,盾盾预先准备好了一段模板 \(A\) 存在了内存中,并以此为基础来打出文章 \(B\)。盾盾每次操作可以将内存中的某一个字符改成另一个字符,或者在某一个位置插入一个字符,或者删除某一个位置上的字符。另外,为了避免自己预存的模板太腿反而浪费时间,盾哥在所有操作之前会斟酌一下选择留下模板 \(A\) 的某一个最优的子串以保证操作次数尽量少(当然盾盾也可以全保留或一个都不留),这一步不计入操作次数。
试求盾盾要打出文章 \(B\) 的最少操作次数。
子串是指母串中连续的一段。
输入格式
输入包含多组数据。
对于每组数据,两行,分别表示 \(A\) 和 \(B\)。
输出格式
每组数据一行,一个数,表示最少操作次数。
输入输出样例
输入样例
aaaaa
aaa
abcabc
bcd
abcdef
klmnopq
输出样例
0
1
7
说明/提示
对于 \(30\%\) 的数据,满足 \(\vert A\vert,\vert B\vert\leq10\)。
对于 \(100\%\) 的数据,满足 \(\vert A\vert,\vert B\vert\leq1000\),数据组数小于等于 \(10\),且输入的串中只含有小写字母。
题解
很明显与字符串的编辑距离有关,不会的参见此处。
区别仅仅在于,本题可以选择一个子串开始转化。
选择一个子串,即可以从前面删去一段,再从后面删去一段。
参考编辑距离,设定状态 \(dp_{i,j}\) 表示将 \(a[1,i]\) 转化为 \(b[1,j]\) 的最少方案数。
对于从前面删去一段,令 \(f_{i,0}=0\) 即可。
令 \(lena,lenb\) 分别表示字符串 \(a,b\) 的长度,答案为:
\(i\) 取小于 \(lena\) 时即忽略了 \(a[i+1,lena]\) 的部分。
AC 代码
时间复杂度:\(\mathcal O\left(n^2\right)\)。
//#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<ctime>
#include<deque>
#include<queue>
#include<stack>
#include<list>
using namespace std;
constexpr const int N=1000;
char a[N+1+1],b[N+1+1],tmp[N+1+1];
int lena,lenb,dp[N+1][N+1];
int main(){
/*freopen("test.in","r",stdin);
freopen("test.out","w",stdout);*/
while(~scanf("%s%s",a+1,b+1)){
lena=strlen(a+1);
lenb=strlen(b+1);
memset(dp,0,sizeof(dp));
for(int j=1;j<=lenb;j++){
dp[0][j]=j;
}
for(int i=1;i<=lena;i++){
for(int j=1;j<=lenb;j++){
dp[i][j]=min(dp[i-1][j],dp[i][j-1])+1;
dp[i][j]=min(dp[i][j],dp[i-1][j-1]+(a[i]!=b[j]));
}
}
int ans=dp[lena][lenb];
for(int i=0;i<lena;i++){
ans=min(ans,dp[i][lenb]);
}printf("%d\n",ans);
}
fclose(stdin);
fclose(stdout);
return 0;
}

浙公网安备 33010602011771号