BZOJ 1055: [HAOI2008]玩具取名 記憶化搜索
題目:
1055: [HAOI2008]玩具取名
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 409 Solved: 255
[Submit][Status][Discuss]
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
II
WW
WW
IG
IIII
Sample Output
IN
HINT
W可以变成II所以IIII可以缩成WW
IN均能变成WW所以WW又可以缩成I或者N
所以最终答案应该按照“WING”的顺序输出IN
[数据范围]
30%数据满足Len<=20,W、I、N、G<=6
100%数据满足Len<=200,W、I、N、G<=16
Source
分析:
dp[i][j][k]表示從i到j是否可以由第k個字符轉化來
用記憶化搜索做的話,邊界條件比較好控制些~~
搜索函數dfs(L,r)
我們可以枚舉中間分界點i,通過判斷區間[L,i]轉化為字符j,區間[i+1,r]
轉化的字符k,判斷字符jk是否可以轉化為一個字符
/* 題目: 某人有一套玩具,并想法给玩具命名。首先他选择WING四个字母中的任意一 个字母作为玩具的基本名字。然后他会根据自己的喜好,将名字中任意一个 字母用“WING”中任意两个字母代替,使得自己的名字能够扩充得很长。 现 在,他想请你猜猜某一个很长的名字,最初可能是由哪几个字母变形过来的。 分析: dp[i][j][k]表示從i到j是否可以由第k個字符轉化來 用記憶化搜索做的話,邊界條件比較好控制些~~ 搜索函數dfs(L,r) 我們可以枚舉中間分界點i,通過判斷區間[L,i]轉化為字符j,區間[i+1,r] 轉化的字符k,判斷字符jk是否可以轉化為一個字符 */ #include <set> #include <map> #include <cmath> #include <queue> #include <stack> #include <string> #include <vector> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long ll; typedef unsigned long long ull; #define lx(x) (x<<1) #define rx(x) (x<<1|1) #define debug puts("here") #define rep(i,n) for(int i=0;i<n;i++) #define rep1(i,n) for(int i=1;i<=n;i++) #define REP(i,a,b) for(int i=a;i<=b;i++) #define foreach(i,vec) for(unsigned i=0;i<vec.size();i++) #define pb push_back #define RD(n) scanf("%d",&n) #define RD2(x,y) scanf("%d%d",&x,&y) #define RD3(x,y,z) scanf("%d%d%d",&x,&y,&z) #define RD4(x,y,z,w) scanf("%d%d%d%d",&x,&y,&z,&w) /******** program ********************/ const int MAXN = 202; int dp[MAXN][MAXN][4]; int num[4],n; char s[402]; int a[405]; map<char,int> id; vector<int> vec[4][4]; void dfs(int l,int r){ if(dp[l][r][0]!=-1) return; int x = a[l] , y = a[r]; if(l+1==r){ foreach(i,vec[x][y]) dp[l][r][ vec[x][y][i] ] = true; rep(i,4) if(dp[l][r][i]==-1) dp[l][r][i] = 0; return; } // 判斷區間[l,i]轉化為字符j,是否可以與區間[i+1,r]轉化的字符由一個字符轉化而來 for(int i=l;i<r;i++){ dfs(l,i); rep(j,4) if(dp[l][i][j]==1){ dfs(i+1,r); rep(k,4) if(dp[i+1][r][k]==1) foreach(q,vec[j][k]) dp[l][r][vec[j][k][q]] = true; } } rep(i,4) if(dp[l][r][i]==-1) dp[l][r][i] = 0; } int main(){ #ifndef ONLINE_JUDGE freopen("sum.in","r",stdin); //freopen("sum.out","w",stdout); #endif id['W'] = 0; id['I'] = 1; id['N'] = 2; id['G'] = 3; rep(i,4) RD(num[i]); rep(i,4) rep(j,num[i]){ scanf("%s",s); vec[ id[ s[0] ] ][ id[ s[1] ] ].pb(i); } scanf("%s",s+1); n = strlen(s+1); memset(dp,-1,sizeof(dp)); rep1(i,n){ a[i] = id[s[i]]; dp[i][i][a[i]] = 1; } dfs(1,n); bool ok = false; s[0] = 'W'; s[1] = 'I'; s[2] = 'N'; s[3] = 'G'; for(int i=0;i<4;i++) if(dp[1][n][i]){ ok = true; printf("%c",s[i]); } if(!ok) puts("The name is wrong!"); else puts(""); return 0; }