POJ2192解题报告

这道题目比较有意思,给定三个字符串,判断第三个字符串是不是前两个字符串中的字符组成的,而且,在前两个字符串中的字符要与原串中的顺序一致才行。例如,cat tree cattree就可以,但是tretac就不行了。解决这个我首先想到的是使用递归的方法解决:用三个变量记录三个字符串的扫描位置,初始都是0,然后递归遍历每个字符,判断是否于第三串中相等,相等则游移一位。代码如下:

#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。现在递归的解法有了,要想使用动态规划解决这个问题,还需要:
  1. 提炼出递归表达式:自顶向下分析
  2. 确认有重复的子问题
  3. 自底向上求解
这个问题的重叠的子问题,并不明显,需要前两个字符串在相同位置的字符相同的时候才会出现。像cat tree cattree就没有重叠的子问题。至于递归表达式,我们令dp[i][j]表示第一个串的前i和第二个串的前j个字符能够组成第三个字符串的前i + j个字符。它可以由一下三个的true或者false决定:
  1. dp[i - 1][j - 1]
  2. dp[i -  1][j]
  3. 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;
}

其实,三个条件,第一个可以省略。

转载于:https://www.cnblogs.com/sing1ee/archive/2012/02/01/2765003.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值