[HAOI2008] 玩具取名 - 区间dp

Posted mollnn

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[HAOI2008] 玩具取名 - 区间dp相关的知识,希望对你有一定的参考价值。

某人有一套玩具,并想法给玩具命名。首先他选择WING四个字母中的任意一个字母作为玩具的基本名字。然后他会根据自己的喜好,将名字中任意一个字母用“WING”中任意两个字母代替,使得自己的名字能够扩充得很长。现在,他想请你猜猜某一个很长的名字,最初可能是由哪几个字母变形过来的。(n leq 200)

Solution

老生常谈的区间 dp

(f[i][j][k]) 表示能否将 ([i,j]) 压成 (k) 这个字母,(g[i][j][k]) 表示 (i,j) 这两个字母能否合成 (k) 这个字母,则
[ f[i][k][p] and f[k+1][j][q] and g[p][q][l] o f[i][j][l] ]
边界 (f[i][i][?]=1)

暴力转移即可

#include <bits/stdc++.h>
using namespace std;

const int N = 205;

int f[N][N][4],g[4][4][4],n,a[N],m[4];

int tr(char c) {
    if(c=='W') return 0;
    if(c=='I') return 1;
    if(c=='N') return 2;
    if(c=='G') return 3;
}

signed main() {
    string str;
    for(int i=0;i<4;i++) cin>>m[i];
    for(int i=0;i<4;i++) {
        for(int j=1;j<=m[i];j++) {
            cin>>str;
            g[tr(str[0])][tr(str[1])][i]=1;
        }
    }
    cin>>str;
    n=str.length();
    for(int i=1;i<=n;i++) a[i]=tr(str[i-1]);
    for(int i=1;i<=n;i++) f[i][i][a[i]]=1;
    for(int le=2;le<=n;le++) {
        for(int i=1;i+le-1<=n;i++) {
            int j=i+le-1;
            for(int k=i;k<j;k++) {
                for(int p=0;p<4;p++) {
                    for(int q=0;q<4;q++) {
                        for(int l=0;l<4;l++) {
                            f[i][j][l]|=f[i][k][p]&f[k+1][j][q]&g[p][q][l];
                        }
                    }
                }
            }
        }
    }
    int flag = 0;
    if(f[1][n][0]) cout<<"W", flag=1;
    if(f[1][n][1]) cout<<"I", flag=1;
    if(f[1][n][2]) cout<<"N", flag=1;
    if(f[1][n][3]) cout<<"G", flag=1;
    if(flag==0) cout<<"The name is wrong!"<<endl;
}

以上是关于[HAOI2008] 玩具取名 - 区间dp的主要内容,如果未能解决你的问题,请参考以下文章

bzoj1055[HAOI2008]玩具取名 区间dp

[HAOI2008] 玩具取名 - 区间dp

[bzoj1055][HAOI2008]玩具取名_区间dp

玩具取名「HAOI2008」

bzoj1055: [HAOI2008]玩具取名(dp)

[luogu4290 HAOI2008]玩具取名(DP)