#include
#include
using namespace std;
char a[201], b[201], c[401];
int al, bl, cl;
int form(int ai, int bi, int ci) {
if (ai == al - 1) return 1;
if (ai == al - 1 && bi == bl - 1) return 0;
int r1 = 0, r2 = 0;
if (ai < al && c[ci] == a[ai])
r1 = form(ai + 1, bi, ci + 1);
if (bi < bl && c[ci] == b[bi])
r2 = form(ai, bi + 1, ci + 1);
return r1 || r2;
}
int main() {
int n;
cin >> n;
for (int i = 1; i <= n; ++i) {
cin >> a >> b >> c;
al = strlen(a);
bl = strlen(b);
cl = strlen(c);
if (form(0, 0, 0))
cout << "Data set " << i << ": yes" << endl;
else
cout << "Data set " << i << ": no" << endl;
}
return 0;
}
提交,结果可想而知,TLE。现在递归的解法有了,要想使用动态规划解决这个问题,还需要:
- 提炼出递归表达式:自顶向下分析
- 确认有重复的子问题
- 自底向上求解
这个问题的重叠的子问题,并不明显,需要前两个字符串在相同位置的字符相同的时候才会出现。像cat tree cattree就没有重叠的子问题。至于递归表达式,我们令dp[i][j]表示第一个串的前i和第二个串的前j个字符能够组成第三个字符串的前i + j个字符。它可以由一下三个的true或者false决定:
- dp[i - 1][j - 1]
- dp[i - 1][j]
- dp[i][j - 1]
对于第一个如果a[i]和b[j]能够组成c[i + j - 1]和c[i + j],则dp[i][j]就是true,否则为false。以此判断,上面的三个式子,可以得到三个bool值,这三个之间是“或”的关系。得动态规划代码如下:
#include
#include
using namespace std;
char a[201], b[201], c[401];
bool dp[201][201];
int al, bl, cl;
int main() {
int n;
cin >> n;
for (int k = 1; k <= n; ++k) {
cin >> a >> b >> c;
al = strlen(a);
bl = strlen(b);
cl = strlen(c);
memset(dp, false, sizeof(dp));
dp[0][0] = true;
for (int i = 1; i <= al; ++i) {
if (dp[i - 1][0]) {
dp[i][0] = a[i - 1] == c[i - 1];
}
}
for (int i = 1; i <= bl; ++i) {
if (dp[0][i - 1]) {
dp[0][i] = b[i - 1] == c[i - 1];
}
}
for (int i = 1; i <= al; ++i)
for (int j = 1; j <= bl; ++j) {
if (dp[i - 1][j - 1]) {
dp[i][j] = a[i - 1] == (c[i + j - 1] && b[i - 1] == c[i + j - 2]) || (a[i - 1] == c[i + j - 2] && b[i - 1] == c[i + j - 1]) || dp[i][j];
}
if (dp[i][j - 1]) {
dp[i][j] = b[j - 1] == c[i + j - 1] || dp[i][j];
}
if (dp[i - 1][j]) {
dp[i][j] = a[i - 1] == c[i + j - 1] || dp[i][j];
}
}
if (dp[al][bl])
cout << "Data set " << k << ": yes" << endl;
else
cout << "Data set " << k << ": no" << endl;
}
return 0;
}
其实,三个条件,第一个可以省略。