bzoj 1055: [HAOI2008]玩具取名(区间DP)

1055: [HAOI2008]玩具取名

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


dp[i][j][1]表示区间[i, j]是否可以用字母'W'表示

dp[i][j][2]表示区间[i, j]是否可以用字母'I'表示

dp[i][j][3]表示区间[i, j]是否可以用字母'N'表示

dp[i][j][4]表示区间[i, j]是否可以用字母'G'表示(1or0)

如果dp[i][j][1]==1,dp[j+1][k][2]==1,并且'WI'可以用'N'表示,那么dp[i][k][3]=1

其它同理

复杂度O(64n^3)

#include<stdio.h>
#include<string.h>
char str[205];
int a[66], b[66], c[66], dp[205][205][5];
int Jud(char ch)
{
	switch(ch)
	{
		case 'W':  return 1;
		case 'I':  return 2;
		case 'N':  return 3;
		default:  return 4;
	}
}
int main(void)
{
	int n, m, i, j, k, p;
	scanf("%d%d%d%d", &n, &j, &k, &p);
	for(i=1;i<=n;i++)
	{
		scanf("%s", str+1);
		a[i] = Jud(str[1]);
		b[i] = Jud(str[2]);
		c[i] = 1;
	}
	for(i=n+1;i<=n+j;i++)
	{
		scanf("%s", str+1);
		a[i] = Jud(str[1]);
		b[i] = Jud(str[2]);
		c[i] = 2;
	}
	for(i=n+j+1;i<=n+j+k;i++)
	{
		scanf("%s", str+1);
		a[i] = Jud(str[1]);
		b[i] = Jud(str[2]);
		c[i] = 3;
	}
	for(i=n+j+k+1;i<=n+j+k+p;i++)
	{
		scanf("%s", str+1);
		a[i] = Jud(str[1]);
		b[i] = Jud(str[2]);
		c[i] = 4;
	}
	m = n+j+k+p;
	scanf("%s", str+1);
	n = strlen(str+1);
	for(i=1;i<=n;i++)
		dp[i][i][Jud(str[i])] = 1;
	for(k=1;k<=n-1;k++)
	{
		for(i=1;i+k<=n;i++)
		{
			for(j=1;j<=i+k-1;j++)
			{
				for(p=1;p<=m;p++)
				{
					if(dp[i][j][a[p]] && dp[j+1][i+k][b[p]])
						dp[i][i+k][c[p]] = 1;
				}
			}
		}
	}
	if(dp[1][n][1]==0 && dp[1][n][2]==0 && dp[1][n][3]==0 && dp[1][n][4]==0)
		printf("The name is wrong!");
	if(dp[1][n][1])
		printf("W");
	if(dp[1][n][2])
		printf("I");
	if(dp[1][n][3])
		printf("N");
	if(dp[1][n][4])
		printf("G");
	printf("\n");
	return 0;
}


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值