1. 程式人生 > 實用技巧 >玩具取名(區間dp)

玩具取名(區間dp)

題目描述

某人有一套玩具,並想法給玩具命名。首先他選擇WING四個字母中的任意一個字母作為玩具的基本名字。然後他會根據自己的喜好,將名字中任意一個字母用“WING”中任意兩個字母代替,使得自己的名字能夠擴充得很長。
現在,他想請你猜猜某一個很長的名字,最初可能是由哪幾個字母變形過來的。 輸入描述:
第一行四個整數W、I、N、G。表示每一個字母能由幾種兩個字母所替代。 接下來W行,每行兩個字母,表示W可以用這兩個字母替代。
接下來I行,每行兩個字母,表示I可以用這兩個字母替代。 接下來N行,每行兩個字母,表示N可以用這兩個字母替代。
接下來G行,每行兩個字母,表示G可以用這兩個字母替代。 最後一行一個長度不超過Len的字串。表示這個玩具的名字。

輸出描述:

一行字串,該名字可能由哪些字母變形而得到。(按照WING的順序輸出) 如果給的名字不能由任何一個字母變形而得到則輸出“The name
is wrong!”

示例1
輸入

1 1 1 1
II
WW
WW
IG
IIII

輸出

IN

思路:
首先設定一個數組sum[5],代表第i個字元能替換成多少種兩個字元
然後設定一個三維陣列a[4][20][2],i代表第幾個字元,j代表他可以替換的種類,k代表替換的具體兩個字元
然後讀入每個字元可以替換的數量以及具體替換種類:
char s[MMAX];
int dp[MMAX][MMAX][5],num[5];
int a[4][20][2];  ///a[i][j][k]中i代表wing
int main()
{
    for(int i=1; i<=4; i++) scanf("%d",&num[i]);
    for(int i=1; i<=4; i++) {
        for(int j=1; j<=num[i]; j++) {
            scanf("%s",s);
            for(int k=0; k<=1; k++) {
                if(s[k]=='W') a[i][j][k]=1;
                if(s[k]=='I') a[i][j][k]=2;
                if(s[k]=='N') a[i][j][k]=3;
                if(s[k]=='G') a[i][j][k]=4;
            }
        }
    }
    scanf("%s",s+1);
}

 讀入字串後初始化dp陣列:

scanf("%s",s+1);
    int len=strlen(s+1);
    memset(dp,0,sizeof(dp));
    for(int i=1; i<=len; i++)
    {
        if(s[i]=='W') dp[i][i][1]=1;
        if(s[i]=='I') dp[i][i][2]=1;
        if(s[i]=='N') dp[i][i][3]=1;
        if(s[i]=='G') dp[i][i][4]=1;
    }

  按照區間dp的模板先列舉長度,然後列舉起點,確定終點,確定完起點終點後可以先遍歷確定需要該區間是否可以組成W或者I或者N或者G,然後遍歷每個字元的替換條件,判斷是否符合條件,具體見程式碼:

for(int le=2; le<=len; le++) ///列舉長度
    {
        for(int l=1; l<=len-le+1; l++) ///列舉起點
        {
            int r=l+le-1; ///確定終點
            for(int kk1=1; kk1<=4; kk1++) ///確定需要滿足什麼條件
            {
                if(dp[l][r][kk1]==1) continue; ///說明已經滿足
                for(int kk=l;kk<r;kk++) ///列舉斷點
                {
                    for(int k=1;k<=num[kk1];k++) ///判斷是否滿足kk1的條件
                    {
                        if(dp[l][kk][a[kk1][k][0]]==1&&dp[kk+1][r][a[kk1][k][1]]==1)
                            dp[l][r][kk1]=1;
                        if(dp[l][r][kk1]==1) break;
                    }
                    if(dp[l][r][kk1]==1) break;
                }
            }
        }
    }

  最後不要忘了是否無字元滿足條件:

int su=0;
    for(int i=1;i<=4;i++)
    {
        if(dp[1][len][i]==1)
        {
            su++;
            if(i==1) printf("W");
            if(i==2) printf("I");
            if(i==3) printf("N");
            if(i==4) printf("G");
        }
    }
    if(su==0) printf("The name is wrong!");
    printf("\n");

最終程式碼為 :

#include<bits/stdc++.h>
#include<cstdio>
#define ll long long
using namespace std;
const int MMAX=2e2+5;
char s[MMAX];
int dp[MMAX][MMAX][5],num[5];
int a[4][20][2];  ///a[i][j][k]中i代表wing
int main()
{
    for(int i=1; i<=4; i++) scanf("%d",&num[i]);
    for(int i=1; i<=4; i++) {
        for(int j=1; j<=num[i]; j++) {
            scanf("%s",s);
            for(int k=0; k<=1; k++) {
                if(s[k]=='W') a[i][j][k]=1;
                if(s[k]=='I') a[i][j][k]=2;
                if(s[k]=='N') a[i][j][k]=3;
                if(s[k]=='G') a[i][j][k]=4;
            }
        }
    }
    scanf("%s",s+1);
    int len=strlen(s+1);
    memset(dp,0,sizeof(dp));
    for(int i=1; i<=len; i++)
    {
        if(s[i]=='W') dp[i][i][1]=1;
        if(s[i]=='I') dp[i][i][2]=1;
        if(s[i]=='N') dp[i][i][3]=1;
        if(s[i]=='G') dp[i][i][4]=1;
    }
    for(int le=2; le<=len; le++) ///列舉長度
    {
        for(int l=1; l<=len-le+1; l++) ///列舉起點
        {
            int r=l+le-1; ///確定終點
            for(int kk1=1; kk1<=4; kk1++) ///確定需要滿足什麼條件
            {
                if(dp[l][r][kk1]==1) continue; ///說明已經滿足
                for(int kk=l;kk<r;kk++) ///列舉斷點
                {
                    for(int k=1;k<=num[kk1];k++) ///判斷是否滿足kk1的條件
                    {
                        if(dp[l][kk][a[kk1][k][0]]==1&&dp[kk+1][r][a[kk1][k][1]]==1)
                            dp[l][r][kk1]=1;
                        if(dp[l][r][kk1]==1) break;
                    }
                    if(dp[l][r][kk1]==1) break;
                }
            }
        }
    }
    int su=0;
    for(int i=1;i<=4;i++)
    {
        if(dp[1][len][i]==1)
        {
            su++;
            if(i==1) printf("W");
            if(i==2) printf("I");
            if(i==3) printf("N");
            if(i==4) printf("G");
        }
    }
    if(su==0) printf("The name is wrong!");
    printf("\n");
    return 0;
}