HDU-6170 Two strings - 2017 Multi-University Training Contest - Team 9(DP)

11 篇文章 0 订阅

题意:

给两个字符串,第一个串全部由字母组成。第二个串由字母和'.'和'*'组成,其中'.'可以代替任何字母,A*代表字母A可以为任意个数,也可以为空,注意可能存在".*"这种情况,另外题目保证*不会单独出现。

思路:

乍一看像个思维题,但情况太多了,分析分析会发现具有状态转移性质。令第二个串为s1,第一个串为s2。

DP[i][j]表示s1串前i个字符去匹配s2串前j个字符能否成功。

所以我们第一层枚举s1的长度,第二层枚举s2的长度进行操作就好。不过存在'*'时的情况有点复杂,注意细节就好了,我的思路细节看代码。。


代码:

#include <bits/stdc++.h>
const int maxn = 2505;
bool dp[maxn][maxn];
char s1[maxn], s2[maxn];
int main()
{
	//freopen("in.txt", "r", stdin);
	int t; scanf("%d", &t);
	while(t--)
	{
		scanf("%s %s", s2+1, s1+1);
		int len1 = strlen(s1+1), len2 = strlen(s2+1);
		memset(dp, 0, sizeof dp);
		dp[0][0] = 1; s1[0] = s2[0] = '@';
		for(int i = 2; i <= len1 && s1[i] == '*'; i+=2) dp[i][0] = 1;
		//我的这个预处理在我代码中是关键。代表前面若干A*(任意字母和*)都可以完全不匹配字符
		for(int i = 1; i <= len1; ++i)
		{
			int keep = 1, tmp;
			for(int j = 1; j <= len2; ++j)
			{
				//字母和'.'的情况直接转移
				if(s1[i] != '.' && s1[i] != '*')
				{
					dp[i][j] = (dp[i-1][j-1] && s1[i] == s2[j]);
				}
				else if(s1[i] == '.')
				{
					dp[i][j] = dp[i-1][j-1];
				}
				else
				{
					dp[i][j] = dp[i-2][j];//代表A*段可以不匹配字符
					if(s1[i-1] == '.')
					{
						if(keep == 1) tmp = dp[i-2][j-1];
						else tmp = (tmp||dp[i-2][j-1]);
						dp[i][j] = (tmp||dp[i][j]);
					}
					else if(s1[i-1] == s2[j])
					{
						if(keep == 1) tmp = dp[i-2][j-1];
						else tmp = (tmp||dp[i-2][j-1]);
						dp[i][j] = (tmp||dp[i][j]);
					}
				}
				if(s2[j+1] == s2[j]) ++keep;
				else keep = 1;
				//keep代表s2串到达j时与其直接的前面重复的个数
				//用于优化上述A*时确定dp[i][j]
				//个数不为1时A*情况可以从前面若干个位置转移过来,所以上述优化减掉了一个for循环
			}
		}
		if(dp[len1][len2]) puts("yes");
		else puts("no");
	}
	return 0;
}


继续加油~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值