原题链接:
hdu
题意简述
给定两个字符串,第一个只有小写字母,第二个除了小写字母外,还有两个特殊字符
′
.
′
'.'
′.′和
′
∗
′
'*'
′∗′。其中
′
.
′
'.'
′.′表示通配符,啥都能配上。
′
∗
′
'*'
′∗′珂以让紧前面的单个字符出现任意多次。(而且。。。任意次后这个
∗
*
∗珂以保留或不保留,也就是说有继续用的珂能)(比如
a
∗
a*
a∗珂以变成(空),
a
a
a,
a
a
aa
aa,
a
a
a
aaa
aaa…)。请你匹配两个字符串。
对于一组数据,如果能配上,输出 y e s yes yes,否则输出 n o no no。
数据
输入
多组数据。第一行是一个
T
(
T
<
=
15
)
T(T<=15)
T(T<=15),表示有
T
T
T组数据。
接下来
2
T
2T
2T行,每两行表示一组数据,是两行字符串(长度
<
=
2500
<=2500
<=2500,平方做法)。
输出
对于每组数据,输出答案。
样例
输入
3
aa
a*
abb
a.*
abb
aab
输出
yes
yes
no
思路
首先说明这个是一个非常毒瘤的字符串 D P DP DP。
2500 2500 2500的数据, n 2 n^2 n2是珂以过的。根据这种 D P DP DP的套路,不妨设 d p [ i ] [ j ] dp[i][j] dp[i][j]为:第二个匹配到 i i i,第一个匹配到 j j j,是否能匹配( b o o l bool bool类型)。
(问:为啥是二配一而不是一配二?答:因为这里二特殊,以前的字符串是两个平等,所以让一配二)
然后开始推方程。
首先边界是很明显的: d p [ 0 ] [ 0 ] = t r u e dp[0][0]=true dp[0][0]=true(空配空自然是配上了)
然后我们会发现,如果我们当前位置 i i i是一个 ∗ * ∗,那么我们就珂以通过神奇的操作把串 2 2 2变成一个空串。所以此时 d p [ i ] [ 0 ] = t r u e dp[i][0]=true dp[i][0]=true。
接着我们去枚举和 1 1 1串配到的位置,设为 j j j。如果串 2 2 2的 i i i位置和串 1 1 1的 j j j位置相等,那么 d p [ i ] [ j ] dp[i][j] dp[i][j]很明显就是 d p [ i − 1 ] [ j − 1 ] dp[i-1][j-1] dp[i−1][j−1]了。当然,这个相等还包括通配符。
如果串 2 2 2的 i i i位置是 ∗ * ∗,那么就有点意思了。我们珂以通过让前面的串出现 0 0 0次的膜法让 d p [ i ] [ j ] dp[i][j] dp[i][j]这个状态珂以通过 d p [ i − 1 ] [ j ] dp[i-1][j] dp[i−1][j]和 d p [ i − 2 ] [ j ] dp[i-2][j] dp[i−2][j]转移,就看你保不保留 ∗ * ∗字符了。当然,这个更新关系是或上去的,因为只要一个能匹配我们就能匹配。当然,如果串 1 1 1的 j j j位置和 j − 1 j-1 j−1位置相等,此时如果 d p [ i − 1 ] [ j − 1 ] dp[i-1][j-1] dp[i−1][j−1]或 d p [ i ] [ j − 1 ] dp[i][j-1] dp[i][j−1]成立,我们就珂以通过复制一次使得两串匹配。
至此我们就差不多有方程了。代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
namespace Flandle_Scarlet
{
#define N 2510
bool dp[N][N];
char s1[N],s2[N];int n1,n2;
void Input()
{
scanf("%s%s",s1+1,s2+1);
n1=strlen(s1+1),n2=strlen(s2+1);
}
void Soviet()
{
memset(dp,0,sizeof(dp));
dp[0][0]=1;//边界
for(int i=1;i<=n2;++i)
{
if (s2[i]=='*') dp[i][0]=1;
for(int j=1;j<=n1;++j)//转移
{
if (s2[i]=='.' or s2[i]==s1[j])
{
dp[i][j]=dp[i-1][j-1];
}
else if (s2[i]=='*')
{
dp[i][j]=(dp[i-1][j] or dp[i-2][j]);
if (s1[j]==s1[j-1] and (dp[i-1][j-1] or dp[i][j-1]))
{
dp[i][j]=1;
}
}
}
}
puts(dp[n2][n1]?"yes":"no");//输出是否有解
}
void IsMyWife()
{
if (0)
{
freopen("","r",stdin);
freopen("","w",stdout);
}
int t;scanf("%d",&t);
while(t--)
{
Input();
Soviet();
}
}
};
int main()
{
Flandle_Scarlet::IsMyWife();
return 0;
}
本文深入解析了一种针对复杂字符串匹配问题的DP算法,详细介绍了如何处理包含特殊字符的模式串,实现对目标字符串的有效匹配。文章通过实例讲解了状态定义、边界条件设定及状态转移方程的推导过程。
1147

被折叠的 条评论
为什么被折叠?



