玩具取名(區間dp)
阿新 • • 發佈:2020-10-21
題目描述
某人有一套玩具,並想法給玩具命名。首先他選擇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; }