1. 程式人生 > >Hdu 6170 Two strings【思維+Dp】

Hdu 6170 Two strings【思維+Dp】

Two strings

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


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

題目大意:

給出兩個字串,第一個字串只包含小寫或者大寫字母,第二個字串包含小寫或者大寫字母或者特殊字元“.”和“*”,這裡“.”可以替換為任意字元,但是不能變成空。

這裡“a*”可以變成空串,可以變成a,也可以是aa,也可以是aaa,還可以是aaaa.以此類推,不限長度。

問第二個串和第一個串是否能夠完全相等。

思路:

觀察到資料範圍,如果是貪心做法的話,資料範圍肯定不能這麼小,而且仔細考慮一下,直接貪心O(n)掃顯然有紕漏;

那麼我們考慮Dp,設定Dp【i】【j】表示串2到位子i,實際匹配串1到位子j的方案是否存在。

那麼不難想到其狀態轉移方程:

①if(b[i]是大寫字母或者是小寫字母)Dp【i】【j】=Dp【i-1】【j-1】&&(a【i】==a【j】);

②if(b[i]是“.”)Dp【i】【j】=Dp【i-1】【j-1】;

③if(b[i]是“*”):

Dp【i】【j】=max(Dp【i-1】【j】,Dp【i】【j】);

Dp【i】【j】=max(Dp【i-2】【j】,Dp【i】【j】);

Dp【i】【j】=max(Dp【i-1】【k~j-1】,Dp【i】【j】);位子k到位子j-1之間的字元要保證都相等。

我們發現暴力去搞的話時間複雜度最壞可以達到O(n^3),那麼我們考慮優化,很顯然位子k是可以進行二分的,但是時間複雜度還是O(n^2logn)依然不低,但是我們可以維護一個數組pre【j】,表示和a【j】相等的字串的最前邊的位子,也就是我們的k,可以在Dp的過程維護,那麼我們只要再求一個Dp的字首和優化一下就能夠達到O(n)了;那麼狀態轉移方程③可以進行優化為:

Dp【i】【j】=max(Sum【i-1】【j-1】-Sum【i-1】,Dp【i】【j】);位子k到位子j-1之間的字元要保證都相等。

注意初始化,就沒有別的什麼了。

Ac程式碼:

#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
char a[2600];
char b[2600];
bool dp[2600][2600];
int pre[2600];
int Is_or[2600][2600];
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%s",a+1);
        scanf("%s",b+1);
        int n=strlen(a+1);
        int m=strlen(b+1);
        memset(dp,false,sizeof(dp));
        dp[0][0]=true;
        for(int i=1;i<=m;i++)
        {
            for(int j=0;j<=n;j++)
            {
                if(j==1)pre[j]=j;
                else
                {
                    if(a[j]==a[j-1])pre[j]=pre[j-1];
                    else pre[j]=j;
                }
                if(b[i]=='.')
                {
                    if(j-1>=0)dp[i][j]=dp[i-1][j-1];
                }
                else if(b[i]=='*')
                {
                    if(j==0)dp[i][j]=dp[i-1][j];
                    else
                    {
                        int pos=pre[j];
                        int tmp;
                        if(Is_or[i-1][j-1]-Is_or[i-1][pos-1]>0)tmp=1;
                        else tmp=0;
                        dp[i][j]=tmp;
                    }
                    if(i-1>=0)dp[i][j]=max(dp[i][j],dp[i-1][j]);
                    if(i-2>=0)dp[i][j]=max(dp[i][j],dp[i-2][j]);
                }
                else
                {
                    if(j-1>=0)dp[i][j]=(dp[i-1][j-1])&&(b[i]==a[j]);
                }
                if(j==0)Is_or[i][j]=dp[i][j];
                else Is_or[i][j]=dp[i][j]+Is_or[i][j-1];
            }
        }
        if(dp[m][n]==true)printf("yes\n");
        else printf("no\n");
    }
}