BZOJ 1055: [HAOI2008]玩具取名 記憶化搜索

題目:

1055: [HAOI2008]玩具取名

Time Limit: 10 Sec   Memory Limit: 162 MB
Submit: 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

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

 
[ Submit][ Status][ Discuss]


HOME Back


 

分析:
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;

}

  

 

 

你可能感兴趣的:(2008)