HDU 6170 Two strings( DP+字符串匹配)
http://acm.hdu.edu.cn/showproblem.php?pid=6170
题目大意:
给出两个字符串s1和s2(长度小于等于2500)。
s1是一个正常的包含大小写字母的字符串,s2是一个类似正则表达式的字符串,除了大小写字母,还有 " . " 和 " * " 两种符号。
" . " 表示可以匹配任意一个字母。
" * ”表示前一个字符可以重复出现任意次(包括零)。
解题思路:
一道标准的dp O(n^2)。
用dp[i][j]来表示s2的前i个字符和s1的前j个字符能否匹配。
对于s2的每一个字符都跑一遍s1的全部字符dp,分别会遇到以下几种情况:
1.s2的该字符是 " * ",而且恰好是第二个字符,那么建立dp起点,也就是dp[i][0]=1;
2.s2的该字符是 " . ",那么说明s2的第j个字符匹配s1的第i个字符成立,dp[i][j]=dp[i-1][j-1];
3.s2的该字符是 " * ",而且不是第二个字符,那么首先考虑到的情况是 * 前一个字符出现0次的情况,所以至少有dp[i][j]=max(dp[i-2][j],dp[i-1][j]);
这种情况举例可以是 s1: abb s2: abbc* dp[i][j]=dp[i-2][j]
4.在第3个情况的前提,在 * 对应的前一个字符可能出现非零次时,如果 * 之前的字符都能全部匹配好: dp[i][j-1]==1 而且s1的第j个字符重复了: s1[j]==s1[j-1]的情况下,举例: s1: abbcccc s2: abbc*
那么很显然只要判断 s2[i-1]==s1[j]成立 或者 s2[i-1]=='.' ,这两个满足任意一个都说明 " * "成功匹配到s1的第j个字符。
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<map> #include<stack> #include<queue> #include<vector> #include<bitset> #include<functional> using namespace std; #define LL long long const int INF = 0x3f3f3f3f; int dp[2505][2505]; char s1[2505],s2[2505]; int main() { int t; scanf("%d",&t); while(t--) { scanf("%s%s",s1+1,s2+1); memset(dp,0,sizeof(dp)); int len1=strlen(s1+1),len2=strlen(s2+1); dp[0][0]=1; for(int i=1;i<=len2;i++) { if(s2[i]=='*'&&i==2) dp[i][0]=1; for(int j=1;j<=len1;j++) { if(s2[i]=='.') dp[i][j]=dp[i-1][j-1]; else if(s2[i]!='*') { if(s2[i]==s1[j]) dp[i][j]=dp[i-1][j-1]; } else { dp[i][j]=max(dp[i-2][j],dp[i-1][j]); if(dp[i][j-1]&&s1[j]==s1[j-1]) { if(s2[i-1]==s1[j] || s2[i-1]=='.') dp[i][j]=1; } } } } if(dp[len2][len1]) cout<<"yes"<<endl; else cout<<"no"<<endl; } return 0; }