递推 DP,思考状态的递进
题意:
给出一个原串和一个需要匹配的串,当然匹配串有两种操作。
- ‘.’ 可以变成任何字母
∗
可以使得前一个字母变成任何长度>= 0,例如:
a∗,可以变成“aa”,“aaa”甚至把a消失“”
问是否能从匹配串变成原串。
题意:
当前串能不能匹配需要知道之前一个串状态,很明显的dp问题,为什么我当时没有想出来?为什么我要用复杂的dfs去不断超时。
因为匹配串可以增长或者剪短,所以首先需要思考枚举匹配串,然后再思考状态
定义: dp[i][j] 匹配串的长度为i,原串的长度为j是否能匹配,值为1代表可以匹配成功,0代表不可以匹配成功。
假设s1为原串,s2为匹配串。
- 当 s1[j]==s2[i]||s2[i]==′.′ 的时候只能看前一个状态是否可以匹配 dp[i−1][j−1]
- 当
s2[i]==′∗′
,思考
∗
的 功能:当可以删除i-1这个字母的时候:
dp[i−2][j]=true ,当不增也不减的时候 : dp[i−1][j]==true ,当需要增加的时候: (dp[i−1][j−1]==true或者dp[i][j−1])并且s1[j]==s1[j−1]
然后两重循环可以解决。需要一个特判:当 s2[2]==′∗′的时候 dp[2][0]=true
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 2505;
char s1[maxn],s2[maxn];
int dp[maxn][maxn];
int main()
{
//freopen("in.txt","r",stdin);
int t;
scanf("%d",&t);
while(t--) {
memset(dp,0,sizeof(dp));
scanf("%s%s",s1+1,s2+1);
int len1 = strlen(s1+1);
int len2 = strlen(s2+1);
dp[0][0] = 1;
for(int i = 1;i <= len2; i++) {
if(i == 2 && s2[i] == '*') dp[i][0] = true;
for(int j = 1;j <= len1; j++) {
if(s2[i] == s1[j] || s2[i] == '.') dp[i][j] = dp[i-1][j-1];
if(s2[i] == '*') {
if( (dp[i-1][j-1] || dp[i][j-1]) && s1[j] == s1[j-1]) {
dp[i][j] = true;
}
else if(dp[i-1][j] || dp[i-2][j]) {
dp[i][j] = true;
}
}
}
}
if(dp[len2][len1])
printf("yes\n");
else
printf("no\n");
}
return 0;
}