sgu 273Game Po (区间dp)

题意:

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();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值