玩具取名

区间dp

思路挺好想的,不过实现......极其鬼畜
令dp[i][j][k]表示i ->j区间能否合为k,pan[b][c]表示b,c字母能合并为哪些字母。
转移方程:$$dp[l][r][a]=dp[l][r][a] | (dp[l][k][b]\cap dp[k+1][r][c]) K\epsilon [l,r],pan[b][c]==a$$

code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#define max(a,b) a>b?a:b
#define maxn 102
using namespace std;
int w,ii,n,g;
bool dp[206][206][7],t[7][17][17];
int it[7][18][5],num[17];
char str[206];
inline int make(char tmp)
{
	if (tmp=='W') return 1;
	if (tmp=='I') return 2;
	if (tmp=='N') return 3;
	if (tmp=='G') return 4;
	return 0;
}
int main()
{
	cin>>w>>ii>>n>>g;
	for (int i=1;i<=w;++i)
	{	
		char tm[5];
		scanf("%s",tm+1);
		t[1][make(tm[1])][make(tm[2])]=1;
		it[1][++num[1]][1]=make(tm[1]),it[1][num[1]][2]=make(tm[2]);
	} 
	for (int i=1;i<=ii;++i)
	{	
		char tm[5];
		scanf("%s",tm+1);
		t[2][make(tm[1])][make(tm[2])]=1;	
		it[2][++num[2]][1]=make(tm[1]),it[2][num[2]][2]=make(tm[2]);
	} 
	for (int i=1;i<=n;++i)
	{	
		char tm[5];
		scanf("%s",tm+1);
		t[3][make(tm[1])][make(tm[2])]=1;
		it[3][++num[3]][1]=make(tm[1]),it[3][num[3]][2]=make(tm[2]);	
	} 
	for (int i=1;i<=g;++i)
	{	
		char tm[5];
		scanf("%s",tm+1);
		t[4][make(tm[1])][make(tm[2])]=1;
		it[4][++num[4]][1]=make(tm[1]),it[4][num[4]][2]=make(tm[2]);	
	} 
	scanf("%s",str+1);	
	int len=strlen(str+1);
	for (int i=1;i<=len;++i)
	{
		dp[i][i][make(str[i])]=1;
	}
	for (int i=2;i<=len;++i) 
	for (int j=1;j<=len-i+1;++j)
	{
		int k=j+i-1;
		for (int l=j;l<=k;++l) 
		for (int m=1;m<=4;++m)
		for (int o=1;o<=num[m];++o)
        dp[j][k][m]|=(dp[j][l][it[m][o][1]] & dp[l+1][k][it[m][o][2]]);
	}
	int ans[5];
	ans[1]=ans[2]=ans[3]=ans[4]=0;
	for (int i=1;i<=4;++i)
	{
		if (dp[1][len][i]) ans[i]=1;
	}
	if (!ans[1]&&!ans[2]&&!ans[3]&&!ans[4]) cout<<"The name is wrong!";
	else 
	{
		if (ans[1]) cout<<"W";
		if (ans[2]) cout<<"I";
		if (ans[3]) cout<<"N";
		if (ans[4]) cout<<"G";
 	}
	return 0;
}

收获:大力dp就好了

posted @ 2018-10-18 21:01  Splitor  阅读(208)  评论(0编辑  收藏  举报