1. 程式人生 > >HAOI2008玩具取名 區間dp

HAOI2008玩具取名 區間dp

題目大意:某人有一套玩具,並想法給玩具命名。首先他選擇WING四個字母中的任意一個字母作為玩具的基本名字。然後他會根據自己的喜好,將名字中任意一個字母用“WING”中任意兩個字母代替,使得自己的名字能夠擴充得很長。

現在,他想請你猜猜某一個很長的名字,最初可能是由哪幾個字母變形過來的。

對於這個題,發現你要是想維護到所有的情況,就必須每次以兩個字元為一個塊來統計,那樣就會發現十分的麻煩,於是我們就可以想出做法:DP。

這個題並不是一般的dp,一般來說都只會讓你統計最優結構,但這個題只需要通過狀態轉移來將一個大長串變成一個字元即可。

題目小技巧:可以將“WING”這四個字母轉成數字計算,要不處理太麻煩。

定義陣列: rp[l][r][i],表示能否將數字l和數字r壓縮成數字i(實際上是字元)

res[l][r][i] 表示對於區間l,r,能否轉成數字i。

程式碼:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define maxn 205
using namespace std;
int num[5],dp[maxn][maxn][5],list[maxn][3],tot;
char m[maxn];
bool flg;

int check(char
a) { if(a=='W') return 1; if(a=='I') return 2; if(a=='N') return 3; if(a=='G') return 4; } 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++) { char a[5]; scanf
("%s",a); list[++tot][0]=i; list[tot][1]=check(a[0]); list[tot][2]=check(a[1]); } scanf("%s",m+1); int len=strlen(m+1); for(int i=1;i<=len;i++) { dp[i][i][check(m[i])]=1; } for(int i=len;i>=1;i--) for(int j=i+1;j<=len;j++) for(int k=i;k<j;k++) for(int t=1;t<=tot;t++) { if(dp[i][k][list[t][1]] && dp[k+1][j][list[t][2]]) dp[i][j][list[t][0]]=1; } for(int i=1;i<=4;i++) if(dp[1][len][i]) { flg=1; if(i==1) printf("W"); if(i==2) printf("I"); if(i==3) printf("N"); if(i==4) printf("G"); } if(!flg) printf("The name is wrong!\n"); return 0; }