1. 程式人生 > >2017多校訓練賽第九場 HDU 6170 Two String(dp)

2017多校訓練賽第九場 HDU 6170 Two String(dp)

Two strings

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1723    Accepted Submission(s): 680

Problem Description

Giving two strings and you should judge if they are matched.
The first string contains lowercase letters and uppercase letters.
The second string contains lowercase letters, uppercase letters, and special symbols: “.” and “*”.
. can match any letter, and * means the front character can appear any times. For example, “a.b” can match “acb” or “abb”, “a*” can match “a”, “aa” and even empty string. ( “*” will not appear in the front of the string, and there will not be two consecutive “*”.

Input

The first line contains an integer T implying the number of test cases. (T≤15)
For each test case, there are two lines implying the two strings (The length of the two strings is less than 2500).

Output

For each test case, print “yes” if the two strings are matched, otherwise print “no”.

Sample Input

3 aa a* abb a.* abb aab

Sample Output

yes yes no

Source

        最近發現,如果dp好能夠快速解決很多問題,於是來補一波……

        這個題其實有點類似最長公共子串的dp,但是又略微有點不同。我們還是一樣,設dp[i][j]表示第一個串取前i位,第二個串取前j位是否能夠完成匹配。根據題意,如果第i位和第j位相等或者第j位為‘.',那麼可以直接從前一位轉移過來,有轉移方程:dp[i][j]=dp[i-1][j-1]。

        然後就是重點討論一下當第j位為’*‘的時候。這個符號表示它前一位可以重複n次,這個n可以是0,而當n為0的時候相當於去掉兩位(第j位和前一位第j-1位),故可以從dp[i][j-2]轉移過來。然後當n為1的時候,相當於第j位是空的,即第二個串只考慮到第j-1位,故可以從dp[i][j-1]轉移過來。當n為2時,相當於j-1位重複了一次,必須滿足a[i]==a[i-1]且b[j-1]==a[i],那麼可以從dp[i-1][j-1]轉移過來。最後是n大於2的情況,此時相當於是把前一位重複很多次,那麼這個前提條件當然是a[i]==a[i-1]且b[j-1]==a[i],如此,就可以從dp[i-1][j]轉移過來。

        總的來說這樣就完成了dp。可以看出,這題還是很需要認真細緻,不丟掉每一個細節的。具體見程式碼:

#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define N 2510
using namespace std;

char a[N],b[N];
bool dp[N][N];
int n,m;

int main()
{
    int T_T,T=0;
    cin>>T_T;
    while(T_T--)
    {
        scanf("%s",a+1);
        scanf("%s",b+1);
        n=strlen(a+1);
        m=strlen(b+1);
        memset(dp,0,sizeof(dp));
        dp[0][0]=1; if (b[2]=='*') dp[0][2]=1;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                if (a[i]==b[j]||b[j]=='.') dp[i][j]=dp[i-1][j-1];
                if (b[j]=='*')
                {
                    dp[i][j]=dp[i][j-1]|dp[i][j-2];
                    if (a[i]==a[i-1]) dp[i][j]=dp[i-1][j-1]|dp[i-1][j];
                }
            }
        }
        if (dp[n][m]) puts("yes"); else puts("no");
    }
    return 0;
}