题解:盾盾的打字机

洛谷自建题目 数据包

题目

题目描述

盾盾有一个非常有意思的打字机,现在盾哥要用这台打字机来打出一段文章。

由于有了上次的经验,盾盾预先准备好了一段模板 \(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\) 的长度,答案为:

\[\min\limits_{i=0}^{lena}dp_{i,lenb} \]

\(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;
}
posted @ 2025-07-21 21:22  TH911  阅读(4)  评论(0)    收藏  举报