思路:设字符串x的长度为n,y的长度为m,那么答案一定在[0, m]之间,那么可以二分求答案。
d(i, j)表示第一个串前i个字符至少需要经过多少次才能的到第二个串的前j个字符,转移方程d(i, j) = min{d(i-1, j-1) + is_same(a[i], b[j]), d(i-1, j) + 1, d(i, j-1) + 1};
如何判断某个答案mid是否合理?当a串中连续k个字符能够在mid次操作类转换成第二个串,就把d(k, 0)变成0即可。
AC代码
#include <cstdio> #include <cmath> #include <cctype> #include <algorithm> #include <cstring> #include <utility> #include <string> #include <iostream> #include <map> #include <set> #include <vector> #include <queue> #include <stack> using namespace std; #pragma comment(linker, "/STACK:1024000000,1024000000") #define eps 1e-10 #define inf 0x3f3f3f3f #define PI pair<int, int> typedef long long LL; const int maxn = 5000 + 5; char x[maxn], y[55]; int d[maxn][55], n, m; bool is_ok(int len) { d[0][0] = 0; for(int i = 1; i <= n; ++i) d[i][0] = i; for(int i = 1; i <= m; ++i) d[0][i] = i; for(int i = 1; i <= n; ++i){ for(int j = 1; j <= m; ++j) { d[i][j] = d[i-1][j-1] + (x[i] == y[j] ? 0 : 1); d[i][j] = min(d[i][j], d[i-1][j] + 1); d[i][j] = min(d[i][j], d[i][j-1] + 1); } if(d[i][m] <= len) d[i][0] = 0; } return d[n][m] <= len; } int bin_search(int l, int r) { while(l < r) { int mid = (l + r) / 2; if(is_ok(mid)) r = mid; else l = mid + 1; } return r; } int main() { int T; scanf("%d", &T); while(T--) { scanf("%s%s", y+1, x+1); n = strlen(x+1), m = strlen(y+1); printf("%d\n", bin_search(0, m)); } return 0; }
如有不当之处欢迎指出!