BZOJ 1055: [HAOI2008]玩具取名 区间dp

Description
  某人有一套玩具,并想法给玩具命名。首先他选择WING四个字母中的任意一个字母作为玩具的基本名字。然后
他会根据自己的喜好,将名字中任意一个字母用“WING”中任意两个字母代替,使得自己的名字能够扩充得很长。
现在,他想请你猜猜某一个很长的名字,最初可能是由哪几个字母变形过来的。
Input
  第一行四个整数W、I、N、G。表示每一个字母能由几种两个字母所替代。接下来W行,每行两个字母,表示W可
以用这两个字母替代。接下来I行,每行两个字母,表示I可以用这两个字母替代。接下来N行,每行两个字母,表示N
可以用这两个字母替代。接下来G行,每行两个字母,表示G可以用这两个字母替代。最后一行一个长度不超过Len的
字符串。表示这个玩具的名字。
Output
  一行字符串,该名字可能由哪些字母变形而得到。(按照WING的顺序输出)如果给的名字不能由任何一个字母
变形而得到则输出“The name is wrong!”

思路:区间动态规划
f{l,r,k}表示字符串s从l到r是否能够转化成k.
转移方程为f{l,r,k}=f{l,j,a}&&f{j+1,r,b} (l<=j<r) k可以转化成ab.
我们采用记忆化搜索将结果存储起来。
遍历t[k](k可以转化的两个字母)
对len进行区间化分进行讨论(l<=j<r).分别讨论dp[l][j][a]&&dp[j+1][r][b].
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class __1055 {
    static int[] t=new int[4];
    static List<String[]> list=new ArrayList<String[]>();
    static int[][][] f=new int[205][205][4];
    static String s;
    static char[] p={'W','I','N','G'};
    static int[] q=new int[255];
    public static boolean dp(int l,int r,int k){
        if(l==r){
            return s.charAt(l)==p[k];
        }
        int res=f[l][r][k];
        if(res!=-1){
            return res==1;
        }
        for(int i=0;i<t[k];++i){
            for(int j=l;j<=r-1;++j){
                if(dp(l,j,q[list.get(k)[i].charAt(0)])&&dp(j+1,r,q[list.get(k)[i].charAt(1)])){
                    f[l][r][k]=1;
                    return true;
                }
            }
        }
        f[l][r][k]=0;
        return false;
    }
    public static void main(String[] args){
        Scanner cin=new Scanner(System.in);
        q['W']=0;  //预处理方便获取当前字符
        q['I']=1;
        q['N']=2;
        q['G']=3;
        for (int i = 0; i < f.length; i++) {
            for (int j = 0; j < f[i].length; j++) {
                for (int k = 0; k < f[i][j].length; k++) {
                    f[i][j][k]=-1;
                }
            }
        } //初始化 -1表示没处理过 0表示可以转化 1表示可以转化
        for(int i=0;i<4;++i){
            t[i]=cin.nextInt();
        }
        for(int i=0;i<4;++i){
            String[] tmp=new String[t[i]];
            for(int j=0;j<t[i];++j){
                tmp[j]=cin.next();
            }
            list.add(tmp);
        }
        s=cin.next();
        int len=s.length()-1;
        boolean flag=false;
        for(int i=0;i<4;++i){
            if(dp(0,len,i)){
                flag=true;
                System.out.print(p[i]);
            }
        }
        if(!flag){
            System.out.println("The name is wrong!");
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值