HAOI2008玩具取名 區間dp
阿新 • • 發佈:2019-02-14
題目大意:某人有一套玩具,並想法給玩具命名。首先他選擇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;
}