Title

CF49E Common ancestor

CF49E Common ancestor

CF

题意

有两个字符串S和T,并提供一些转换方案(每一个方案可以将一个字母转换成两个字母),求S和T是否可以由一个相同的字符串转换出来,如果可以,求最短的字符串,若不行,输出-1。

思路

先不去考虑S和T,先考虑单独去某个字符串是否能够由某一个字母扩展而成。

image

而在实际扩展的过程中是不断使用转换方案的。

image

若原字母能够扩展出一段区间,那么必然存在一种方案,使得原字母先扩展得到两个新字母,并有这两个字母接管两个子区间。

image

对于字符串S和字符串T来说,如果说中间存在由一个相同的字母可以扩展出一段距离的话,那么就不妨尝试将这个字母加入到初始字符串。

image

定义一个dp[i][j]代表着说对于S串前i个元素来说和对于T串前j个元素来说最短的初始字符串。

#include <bits/stdc++.h>
#define N 60

using namespace std;
int rec[N][4];
bool ok[2][N][N][30];
int dp[N][N];

void solve() {
	char s[N], t[N], op[5];
	int n;
	cin >> s + 1 >> t + 1;
	int lens = strlen(s + 1);
	int lent = strlen(t + 1);

	cin >> n;
	for (int i = 0; i < n; i++) {
		cin >> op;

		rec[i][0] = op[0] - 'a';
		rec[i][1] = op[3] - 'a';
		rec[i][2] = op[4] - 'a';
	}
	for (int i = 1; i <= lens; i++)
		ok[0][i][i][ s[i] - 'a' ] = 1;

	for (int i = 1; i <= lent; i++)
		ok[1][i][i][ t[i] - 'a' ] = 1;

	for (int i = 2; i <= lens; i++)
		for (int st = 1; st <= lens - i + 1; st++) {
			int ed = st + i - 1;
			for (int k = st + 1; k <= ed; k++)
				for (int c = 0; c < n; c++) {

					ok[0][st][ed][ rec[c][0] ] |= (ok[0][st][k - 1][ rec[c][1] ] && ok[0][k][ed][ rec[c][2]]);
				}
		}

	for (int i = 2; i <= lent; i++)
		for (int st = 1; st <= lent - i + 1; st++) {
			int ed = st + i - 1;
			for (int k = st + 1; k <= ed; k++)
				for (int c = 0; c < n; c++) {

					ok[1][st][ed][ rec[c][0] ] |= (ok[1][st][k - 1][ rec[c][1] ] && ok[1][k][ed][ rec[c][2]]);
				}
		}

	memset(dp, 0x3f, sizeof(dp));
	dp[0][0] = 0;
	for (int i = 1; i <= lens; i++)
		for (int j = 1; j <= lent; j++)
			for (int k = 1; k <= i; k++)
				for (int l = 1; l <= j; l++)
					for (int c = 0; c < 26; c++)
						if (ok[0][k][i][c] && ok[1][l][j][c])
							dp[i][j] = min(dp[i][j], dp[k - 1][l - 1] + 1);

	if (dp[lens][lent] > 100)
		cout << -1;
	else
		cout << dp[lens][lent];
}

int main() {
	int T_ = 1;
	while (T_--)
		solve();
	return 0;
}
posted @ 2022-04-20 22:06  BeautifulWater  阅读(26)  评论(0编辑  收藏  举报