zoukankan      html  css  js  c++  java
  • NOI2017 游戏

    https://www.luogu.org/problemnew/show/P3825

    如果没有x地图,每场比赛只有两种选择赛车的方案,而且只能选择其中一个

    这是一个2-SAT问题

    对于约束条件 (i,hi,j,hj )

    若hi不能选 ,第i场比赛的可选赛车中不存在hi,所以此条件忽略

    若hj不能选,那么只要第i场比赛选择了赛车hi,就一定不会存在合法方案,所以建边hi-->hi',表示若选择了赛车hi,则一定不合法

    否则,建边 hi-->hj,hj'-->hi',表示若第i场选择赛车hi,则第j场选择赛车hj;第j场选择赛车hj',则第i场选择赛车hi'

    再加上x地图,3-SAT?

    看数据范围,x地图最多只有8张

    那么可以枚举每张x地图是a、b、c

    每次重新构图

    时间复杂度为O((n+m)* 3^n)

    其实a、b、c只枚举两个就可以

    因为如果枚举的是a、b

    a的时候可以选 B、C

    b的时候可以选 A、C

    涵盖了A、B、C 三种情况

    时间复杂度为O((n+m)* 2^n)

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    
    using namespace std;
    
    #define N 50001
    #define M 100001
    
    int n,d,m;
    char s[N];
    
    char ty[N][2];
    
    char ss[N];
    
    struct node
    {
        int a,b;
        char ha,hb;
    }e[M];
    
    int tot;
    int front[N<<1],to[M<<1],nxt[M<<1];
    
    int dfn[N<<1],low[N<<1];
    int st[N<<1],top;
    int bl[N<<1],id;
    bool vis[N<<1];
    
    void read(int &x)
    {
        x=0; char c=getchar();
        while(!isdigit(c)) c=getchar();
        while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
    }
    
    void init()
    {
        read(n); read(d);
        scanf("%s",s+1);
        for(int i=1;i<=n;++i)
            if(s[i]=='a') ty[i][0]='B',ty[i][1]='C';
            else if(s[i]=='b') ty[i][0]='A',ty[i][1]='C';
            else if(s[i]=='c') ty[i][0]='A',ty[i][1]='B';
        read(m);
        char c[3];
        for(int i=1;i<=m;++i)
        {
            read(e[i].a);
            scanf("%s",c); e[i].ha=c[0];
            read(e[i].b);
            scanf("%s",c); e[i].hb=c[0];
        }
    }
    
    void add(int u,int v)
    {
        to[++tot]=v; nxt[tot]=front[u]; front[u]=tot;
    }
    
    void tarjan(int x)
    {
        dfn[x]=low[x]=++tot;
        st[++top]=x;
        vis[x]=true;
        for(int i=front[x];i;i=nxt[i])
            if(!dfn[to[i]]) 
            {
                tarjan(to[i]);
                low[x]=min(low[x],low[to[i]]);
            }
            else if(vis[to[i]]) low[x]=min(low[x],dfn[to[i]]);
        if(low[x]==dfn[x])
        {
            id++;
            while(st[top]!=x) 
            {
                bl[st[top]]=id;
                vis[st[top--]]=false;
            }
            bl[x]=id;
            vis[x]=false;
            top--;
        }
    }
    
    void clear()
    {
        tot=1;
        memset(front,0,sizeof(front));
        memset(dfn,0,sizeof(dfn));
        id=0;
    }
    
    void solve()
    {
        int S=1<<d;
        int cnt;
        int a,b;
        char ha,hb;
        bool tag;
        for(int i=0;i<S;++i)
        {
            cnt=0;
            for(int j=1;j<=n;++j)
                if(s[j]!='x') ss[j]=s[j]-32;
                else 
                {
                    if((1<<cnt++)&i)
                    {
                        ss[j]='A';
                        ty[j][0]='B';
                        ty[j][1]='C';
                    }
                    else
                    {
                        ss[j]='B';
                        ty[j][0]='A';
                        ty[j][1]='C';
                    }
                }
            clear();
            for(int j=1;j<=m;++j)
            {
                a=e[j].a; b=e[j].b;
                ha=e[j].ha; hb=e[j].hb;
                if(ss[a]==ha) continue;
                else if(ss[b]==hb) add(a<<1|(ha==ty[a][1]),a<<1|(ha!=ty[a][1]));
                else
                {
                    add(a<<1|(ha==ty[a][1]),b<<1|(hb==ty[b][1]));
                    if(a!=b) add(b<<1|(hb!=ty[b][1]),a<<1|(ha!=ty[a][1]));
                }
            }
            tot=0;
            for(int j=1;j<=n;++j)
            {
                if(!dfn[j<<1]) tarjan(j<<1);
                if(!dfn[j<<1|1]) tarjan(j<<1|1);
            }
            tag=false;
            for(int j=1;j<=n;++j)
                if(bl[j<<1]==bl[j<<1|1]) { tag=true; break;}
            if(!tag)
            {
                for(int j=1;j<=n;++j)
                    if(bl[j<<1]<bl[j<<1|1]) putchar(ty[j][0]);
                    else putchar(ty[j][1]);
                return;
            }
        }
        printf("-1");
    }
    
    int main()
    {
        init();
        solve();
    }

    题目背景

    狂野飙车是小 L 最喜欢的游戏。与其他业余玩家不同的是,小 L 在玩游戏之余,还精于研究游戏的设计,因此他有着与众不同的游戏策略。

    题目描述

    小 L 计划进行nn 场游戏,每场游戏使用一张地图,小 L 会选择一辆车在该地图上完成游戏。

    小 L 的赛车有三辆,分别用大写字母A、B、C表示。地图一共有四种,分别用小写字母x、a、b、c表示。其中,赛车A不适合在地图a上使用,赛车B不适合在地图b上使用,赛车C不适合在地图c上使用,而地图x则适合所有赛车参加。适合所有赛车参加的地图并不多见,最多只会有d张。

    nn 场游戏的地图可以用一个小写字母组成的字符串描述。例如:S=xaabxcbc表示小 L 计划进行88 场游戏,其中第11 场和第55 场的地图类型是x,适合所有赛车,第22 场和第33 场的地图是a,不适合赛车A,第44 场和第77 场的地图是b,不适合赛车B,第66 场和第88 场的地图是c,不适合赛车C。

    小 L 对游戏有一些特殊的要求,这些要求可以用四元组 (i, h_i, j, h_j)(i,hi,j,hj) 来描述,表示若在第ii 场使用型号为h_ihi 的车子,则第jj 场游戏要使用型号为h_jhj 的车子。

    你能帮小 L 选择每场游戏使用的赛车吗?如果有多种方案,输出任意一种方案。如果无解,输出 “-1’’(不含双引号)。

    输入输出格式

    输入格式:

    输入第一行包含两个非负整数n, dn,d 。

    输入第二行为一个字符串SS 。n, d, Sn,d,S 的含义见题目描述,其中SS 包含nn 个字符,且其中恰好dd 个为小写字母xx 。

    输入第三行为一个正整数mm ,表示有mm 条用车规则。接下来mm 行,每行包含一个四元组i, h_i, j, h_ji,hi,j,hj ,其中i, ji,j 为整数,h_i, h_jhi,hj 为字符a、b或c,含义见题目描述。

    输出格式:

    输出一行。

    若无解输出 “-1’’(不含双引号)。

    若有解,则包含一个长度为nn 的仅包含大写字母A、B、C的字符串,表示小 L 在这nn 场游戏中如何安排赛车的使用。如果存在多组解,输出其中任意一组即可。

    输入输出样例

    输入样例#1: 复制
    3 1
    xcc
    1
    1 A 2 B
    输出样例#1: 复制
    ABA

    说明

    【样例1解释】

    小 L 计划进行33 场游戏,其中第11 场的地图类型是x,适合所有赛车,第22 场和第33 场的地图是c,不适合赛车C。

    小 L 希望:若第11 场游戏使用赛车A,则第22 场游戏使用赛车B。那么为这33 场游戏分别安排赛车A、B、A可以满足所有条件。若依次为33 场游戏安排赛车为BBB或BAA时,也可以满足所有条件,也被视为正确答案。但依次安排赛车为AAB或ABC时,因为不能满足所有条件,所以不被视为正确答案。

     

  • 相关阅读:
    细叠子草—蛤蟆皮草
    JQuery修改对象的属性值
    设计专用色系,挺不错的值得借鉴
    PDF如何自动滚动阅读
    给初级拍摄者的十条好建议
    每天一个linux命令(45):route命令
    每天一个linux命令(44):ifconfig命令
    每天一个linux命令(43):lsof命令
    每天一个linux命令(42):crontab命令
    每天一个linux命令(41):at命令
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/8438244.html
Copyright © 2011-2022 走看看