P4290 玩具取名 【区间dp】


传送门:P4290



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

输入格式
第一行四个整数W、I、N、G。表示每一个字母能由几种两个字母所替代。
接下来W行,每行两个字母,表示W可以用这两个字母替代。
接下来I行,每行两个字母,表示I可以用这两个字母替代。
接下来N行,每行两个字母,表示N可以用这两个字母替代。
接下来G行,每行两个字母,表示G可以用这两个字母替代。
最后一行一个长度不超过Len的字符串。表示这个玩具的名字。

输出格式
一行字符串,该名字可能由哪些字母变形而得到。(按照WING的顺序输出)
如果给的名字不能由任何一个字母变形而得到则输出“The name is wrong!”

输入:

1 1 1 1
II
WW
WW
IG
IIII

输出:

IN



题解:
定义发f[i][j][s]:表示在字符串中i~j这个区间是否可以组合成为字符s

转移很容易就可以想出来:因为如果f[i][k][s1]==f[k+1][j][s2]==1(i<=k<=j) && s1和s2可以组成s,那么f[i][j][s]=1;

具体看代码

AC代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int M=250;
int W,I,N,G;
char s[M];
struct Node
{
    int s1,s2,id;
}st[2*M];
int dp[M][M][M];

int main()
{
    scanf("%d%d%d%d",&W,&I,&N,&G);
    int len=0;
    for(int i=0;i<W;i++)
    {
        scanf("%s",s);
        st[++len].s1=s[0]-'0',st[len].s2=s[1]-'0',st[len].id='W'-'0';
    }
    for(int i=0;i<I;i++)
    {
        scanf("%s",s);
        st[++len].s1=s[0]-'0',st[len].s2=s[1]-'0',st[len].id='I'-'0';
    }
    for(int i=0;i<N;i++)
    {
        scanf("%s",s);
        st[++len].s1=s[0]-'0',st[len].s2=s[1]-'0',st[len].id='N'-'0';
    }
    for(int i=0;i<G;i++)
    {
        scanf("%s",s);
        st[++len].s1=s[0]-'0',st[len].s2=s[1]-'0',st[len].id='G'-'0';
    }
    scanf("%s",s+1);
    int l=strlen(s+1);
    memset(dp,0,sizeof(dp));
    for(int i=1;i<=l;i++)
    {
       
        dp[i][i][s[i]-'0']=1;
    }
    for(int t=2;t<=l;t++)//长度
    {
        for(int i=1;i<=l-t+1;i++)//左端点
        {
            int r=i+t-1;//右端点
            for(int k=i;k<=r;k++)//中间点
            {
                for(int j=1;j<=len;j++)
                {
                    if(dp[i][k][st[j].s1]&&dp[k+1][r][st[j].s2])
                        dp[i][r][st[j].id]=1;
                }
            }
        }
    }

    int flag=0;
    if(dp[1][l]['W'-'0'])
    {
        printf("W");
        flag=1;
    }
    if(dp[1][l]['I'-'0'])
    {
        printf("I");
        flag=1;
    }
    if(dp[1][l]['N'-'0'])
    {
        printf("N");
        flag=1;
    }
    if(dp[1][l]['G'-'0'])
    {
        printf("G");
        flag=1;
    }
    if(flag)
        printf("\n");
    else
        printf("The name is wrong!\n");
    return 0;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值