和之前的一道cf很像,但明显难了很多;
麻瓜的我模仿之前那道一直在模拟,没想到还可以递推,亏我最近还在做什么递推练习TT;
题意:给出原串与匹配串,问能否匹配原串中所有的字符。’.’可以匹配所有字符,‘*’是给前一个字符附加一个buff,使其可以变成0~无穷个同样的字符;
思路:bool dp[i][j]代表str2前i个字符能否和str1前j个字符匹配(因为我们是用1去匹配2嘛,所以把2做i了)
所以先要搞一个大循环枚举str2,然后一个里面再套一个循环枚举str1;
如果str2[i]==’点’ 或者 str1[j]==str2[i];dp[i][j]=dp[i-1][j-1];
然后考虑str2[i]=‘星’;
1::dp[i][j]=max(dp[i-2][j],dp[i-1][j]);如果dp[i-2][j]=1;那_*可以换成空字符使dp[i][j]=1;如果dp[i-1][j]=1;那*可省去;如果都等于那随便取哪种情况,只要能匹配成功就行了;
2::如果str1[j]==str1[j-1]就代表*可取多个字符,所以要考虑dp[i-1][j-1]||dp[i][j-1]是否匹配成功;
最后是其他情况则代表匹配不成功;因为初始化是false,所以可以省略;
ps:如果str2【i】==’*’;则dp[2][0]=1;
因为任意字符搭配*可省略,顺带防止下面re;
咸鱼一只。。。不知道为什么每次比赛完看了官方题解就一下子有思路了;
#include <bits/stdc++.h>
using namespace std;
const int maxn=2555;
char str1[maxn],str2[maxn];
bool dp[maxn][maxn];
int main()
{
int T;
scanf("%d\n",&T);
while(T--)
{
memset(dp,false,sizeof(dp));
scanf("%s%s",str1+1,str2+1);
int l1=strlen(str1+1);
int l2=strlen(str2+1);
dp[0][0]=true;
for(int i=1; i<=l2; i++)
{
if(i==2&&str2[2]=='*')
dp[2][0] = true;
for(int j=1;j<=l1;j++)
{
if(str2[i]=='.'||str1[j]==str2[i])
dp[i][j]=dp[i-1][j-1];
else if(str2[i]=='*')
{
dp[i][j]=max(dp[i-2][j],dp[i-1][j]);
if((dp[i-1][j-1]||dp[i][j-1])&&str1[j-1]==str1[j])
dp[i][j] = true;
}
}
}
if(dp[l2][l1])
puts("yes");
else
puts("no");
}
return 0;
}