Message(codeforces)

Message

问题:给字符串A,字符串B。有三种操作:1,在字符串的前端或后端加上一个字符2,删掉前端或后端一个字符,改变字符串中间一个字符。求将一个A的子串变成B最少的操作数。

我们要求A一个子串,和B的子串有着最大匹配
说一下最大匹配:这个可能是和B的子串相同,也有可能是和B的子串在中间有几个位置不同其他都相同
我们再用B的长度减去最大匹配中相同的字符个数,得到答案。

我见了两种解法。都写写吧。

暴力

借鉴大佬博客 Orz
两遍暴力,每次二重循环求一个串对另一个串的匹配
A:abc
B:bd
匹配过程:
a-b,b-d
b-b,c-d
c-b
(如果还不太清楚就去看看上面的博客)

#include<bits/stdc++.h>
using namespace std;
char A[2010], B[2010];
int dp[2010][2010]; 
int main() {
    
    
	int ans = 0, idx = 0, lena, lenb, u = 0, v = 0;
	A[0] = B[0] = 1; 
	scanf("%s%s", &A[1], &B[1]);
	lena = strlen(A), lenb = strlen(B);
	for(int i=1; i<lena; i++) {
    
    
		u = (A[i] == B[1]);
		for(int j=1; j+1<lenb&&i+j<lena; j++) {
    
    
			u += (A[i+j]==B[j+1]);
		}
		v = max(v, u);
	}
	for(int i=1; i<lenb; i++) {
    
    
		u = (B[i] == A[1]);
		for(int j=1; j+1<lena&&i+j<lenb; j++) {
    
    
			u += (B[i+j] == A[j+1]); 
		}
		v = max(v, u);
	}
	printf("%d", lenb-v-1);
	return 0;
}

动态规划

就解释代码吧

#include<bits/stdc++.h>
using namespace std;
char A[2010], B[2010];
int dp[2010][2010]; 
int main() {
    
    
	int ans = 0, idx = 0, lena, lenb, u, v;
	A[0] = B[0] = 1; 
	scanf("%s%s", &A[1], &B[1]);
	lena = strlen(A), lenb = strlen(B);
	for(int i=1; A[i]; i++) {
    
    
		for(int j=1; B[j]; j++) {
    
    
			ans = max(ans, dp[i][j] = dp[i-1][j-1] + (A[i] == B[j]));
		}
	}
	printf("%d", lenb-ans-1);
	return 0;
}

ans = max(ans, dp[i][j] = dp[i-1][j-1] + (A[i] == B[j]));
dp[i][j]是从dp[i-1][j-1]得到的。我们可以打印dp数组观察最大匹配;
举个例子:A:abcd,B:acc;

dp a c c
a 1 0 0
b 0 1 0
c 0 1 2
d 0 0 1

我们可以发现最大匹配是A:abc,B:acc,相同字符数为2。
解决怎样在中间改变使最少操作数的问题

猜你喜欢

转载自blog.csdn.net/weixin_45363113/article/details/106676436