题意:
4种颜色,两个混合可以组成另一种,给出所有组合以及组合后的结果,给一串颜色,任意位置合并最后合并成一个颜色的所有可能性
tip:
dp[I][j][k]表示从I到j是否可以变成第k个颜色,注意可能有同样两种颜色组合,但形成不一样的颜色,所以我用了前向星把他们连起来,而且从I到j形成的颜色也可能是多个,也用了前向星,循环中间位置m 枚举I到m和m+1到j可能形成的颜色 在循环这两个颜色组成的颜色,就可以更新dp[I][j][k]了,最后枚举dp[1][n][0/1/2/3]谁可能,保存下来即可
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
const int maxn = 201;
bool dp[maxn][maxn][4];
int to[4][4],num[4],mp[26],len,n;
char mpb[4],s[210];
struct node{
int v,next;
}E[4*4*4],edges[maxn*maxn*4];
int first[4][4],tot,tt,head[maxn][maxn];
void add(int u,int m,int v){
E[tt].v = v;E[tt].next = first[u][m];first[u][m] = tt++;
}
void addr(int i,int j,int v){
edges[tot].v = v;edges[tot].next = head[i][j];head[i][j] = tot++;
}
void init(){
tt = tot = 0;
memset(head,-1,sizeof(head));
memset(first,-1,sizeof(first));
for(int i = 0 ; i < 4; i++){
scanf("%d",&num[i]);
}
for(int i = 0 ; i < 4; i++){
for(int j = 0 ; j < num[i]; j++){
scanf("%s",s);
add(mp[s[0]-'a'],mp[s[1]-'a'] , i);
}
}
scanf("%s",s+1);
n = strlen(s+1);
for(int i = 1 ; i <= n ; i++){
dp[i][i][mp[s[i]-'a']] = true;
addr(i,i,mp[s[i]-'a']);
}
}
void sov(){
for(int len = 2; len <= n ; len++){
for(int i = 1 ; i + len-1 <= n; i++){
int j = len+i-1;
for(int m = i ; m < j ; m++){
for(int k = head[i][m] ; k != -1; k = edges[k].next){
int v = edges[k].v;
for(int p = head[m+1][j] ; p != -1 ; p = edges[p].next){
int e = edges[p].v;
for(int an = first[v][e];an != -1 ;an = E[an].next){
if(!dp[i][j][E[an].v])
addr(i,j,E[an].v);
dp[i][j][E[an].v] = true;
}
}
}
}
}
}
}
char ans[4];
void print(){
int cnt = 0;
for(int i = 0 ; i < 4; i++){
if(dp[1][n][i] ){
ans[cnt++] = mpb[i];
}
}
if(cnt == 0) printf("Nobody\n");
else{
for(int i = 0 ; i < cnt ;i++)
printf("%c",ans[i]);
printf("\n");
}
}
int main(){
mp['b'-'a'] = 0;mpb[0] = 'b';
mp['r'-'a'] = 1;mpb[1] = 'r';
mp['y'-'a'] = 2;mpb[2] = 'y';
mp['w'-'a'] = 3;mpb[3] = 'w';
init();
sov();
print();
}