1. 程式人生 > >BZOJ 1055: [HAOI2008]玩具取名

BZOJ 1055: [HAOI2008]玩具取名

命名 str 哪些 desc color 一行 can script rip

Description

某人有一套玩具,並想法給玩具命名。首先他選擇WING四個字母中的任意一個字母作為 玩具的基本名字。然後他會根據自己的喜好,將名字中任意一個字母用“WING”中任意兩個 字母代替,使得自己的名字能夠擴充得很長。現在,他想請你猜猜某一個很長的名字,最初 可能是由哪幾個字母變形過來的。

Input

 第一行四個整數W、I、N、G。表示每一個字母能由幾種兩個字母所替代。接下來W行,每行 兩個字母,表示W可以用這兩個字母替代。接下來I行,每行兩個字母,表示I可以用這兩個字母替代 接下來N行,每行兩個字母,表示N可以用這兩個字母替代。接下來G行,每行兩個字母,表示G可以 用這兩個字母替代。最後一行一個長度不超過Len的
字符串。表示這個玩具的名字。

Output

一行字符串,該名字可能由哪些字母變形而得到。(按照WING的順序輸出)如果給的名字不

能由任何一個字母變形而得到則輸出“The name is wrong!”

Sample Input

1 1 1 1
II
WW
WW
IG
IIII

Sample Output

IN

HINT

W可以變成II所以IIII可以縮成WW IN均能變成WW所以WW又可以縮成I或者N 所以最終答案 該按照“WING”的順序輸出IN
[數據範圍]
100%數據滿足Len<=200,W、I、N、G<=16

題目大意:

一個字母可以多個兩個字母合成,如W可以由WI合成也可以由GI合成。

給定一個字符串,求它最初是由哪幾個字母組成的。

題解:區間dp

f[l][r][i]表示區間[l,r]能否合成i這個字母。

轉移方程為 f[l][r][i]=f[l][r][i]||(f[l][mid][p]&&f[mid+1][r][g])

其中mid為區間的斷點,p,g為合成i的兩個字母。

代碼:1A好開心 -~

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

int len;
bool flag,f[220][220][5
]; char a[220]; struct S{ string s[20]; int cnt; }c[5]; int main(){ scanf("%d%d%d%d",&c[1].cnt,&c[2].cnt,&c[3].cnt,&c[4].cnt); for(int i=1;i<=4;i++) for(int j=1;j<=c[i].cnt;j++) cin>>c[i].s[j]; scanf("%s",a+1);len=strlen(a+1); for(int i=1;i<=len;i++){ int g; if(a[i]==W)g=1; if(a[i]==I)g=2; if(a[i]==N)g=3; if(a[i]==G)g=4; f[i][i][g]=1; } for(int k=2;k<=len;k++){ for(int l=1;l+k-1<=len;l++){ int r=l+k-1; for(int mid=l;mid<r;mid++){ for(int i=1;i<=4;i++){ for(int j=1;j<=c[i].cnt;j++){ int g,p; if(c[i].s[j][0]==W)g=1;if(c[i].s[j][1]==W)p=1; if(c[i].s[j][0]==I)g=2;if(c[i].s[j][1]==I)p=2; if(c[i].s[j][0]==N)g=3;if(c[i].s[j][1]==N)p=3; if(c[i].s[j][0]==G)g=4;if(c[i].s[j][1]==G)p=4; f[l][r][i]=f[l][r][i]||(f[l][mid][g]&&f[mid+1][r][p]); } } } } } for(int i=1;i<=4;i++){ if(f[1][len][i]){ if(i==1)printf("W"); if(i==2)printf("I"); if(i==3)printf("N"); if(i==4)printf("G"); flag=true; } } if(!flag)printf("The name is wrong!"); return 0; }

BZOJ 1055: [HAOI2008]玩具取名