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

    题目描述

    题解:

    假的$3-SAT$,真的$2-SAT$。

    我们可以枚举所有的$x$都是什么,这样做是$O(n*3^d)$的。

    但是考虑到$a$包含了$B$和$C$,$b$包含了$A$和$C$,我们可以不用将$x$改成$c$,改成$a$或$b$就好了。

    将每个地图分为两个点。比如当前为$a$,那么我们可以选$B$或选$C$。

    然后就是$2-SAT$建图。

    当然是根据$m$组限制条件了。

    对于一组限制条件$(i,hi,j,hj)$:

    (1)若$i$不能取$hi$,直接忽略;

    (2)若$j$不能取$hj$,说明$i$取$hi$时直接死,所以$(i,hi)->(i,剩下状态)$;

    (3)一般情况,$(i,hi)->(j,hj)$,$(j,剩下情况)->(i,剩下情况)$。

    然后跑$2-SAT$就好了。

    代码:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int N = 100050;
    int n,d,m,a[N],pos[10];
    char s0[N],s1[10],s2[10];
    struct BAN
    {
        int i,hi,j,hj;
        BAN(){}
        BAN(int i,int hi,int j,int hj):i(i),hi(hi),j(j),hj(hj){}
    }b[N];
    int hed[N],cnt;
    struct EG
    {
        int to,nxt;
    }e[N<<3];
    void ae(int f,int t)
    {
        e[++cnt].to = t;
        e[cnt].nxt = hed[f];
        hed[f] = cnt;
    }
    int dep[N],low[N],tim,bel[N],bc;
    int sta[N],tl;
    bool vis[N];
    void init()
    {
        memset(hed,0,sizeof(hed));
        memset(dep,0,sizeof(dep));
        memset(low,0,sizeof(low));
        memset(bel,0,sizeof(bel));
        memset(vis,0,sizeof(vis));
        cnt = tim = bc = tl = 0;
    }
    int gt(int x,int i)
    {
        if(a[x]<i)return (x<<1)|(i-1);
        return (x<<1)|i;
    }
    void tarjan(int u)
    {
        dep[u]=low[u]=++tim;
        sta[++tl] = u;
        vis[u] = 1;
        for(int j=hed[u];j;j=e[j].nxt)
        {
            int to = e[j].to;
            if(!dep[to])
            {
                tarjan(to);
                low[u]=min(low[u],low[to]);
            }else if(vis[to])
                low[u]=min(low[u],dep[to]);
        }
        if(dep[u]==low[u])
        {
            bc++;
            int c = -1;
            while(c!=u)
            {
                c = sta[tl--];
                vis[c] = 0;
                bel[c] = bc;
            }
        }
    }
    bool check()
    {
        for(int i=1;i<=n;i++)
            if(bel[i<<1]==bel[i<<1|1])return 0;
        return 1;
    }
    void print(int x)
    {
        if(bel[x<<1]<bel[x<<1|1])
            putchar(a[x]==0?'B':'A');
        else    putchar(a[x]==2?'B':'C');
    }
    int main()
    {
        scanf("%d%d%s%d",&n,&d,s0+1,&m);
        for(int i=1,j=0;i<=n;i++)
            if(s0[i]!='x')a[i]=s0[i]-'a';
            else pos[j++]=i;
        for(int x,y,i=1;i<=m;i++)
        {
            scanf("%d%s%d%s",&x,s1,&y,s2);
            b[i]=BAN(x,s1[0]-'A',y,s2[0]-'A');
        }
        for(int i=0;i<(1<<d);i++)
        {
            init();
            for(int j=0;j<d;j++)
                a[pos[j]] = ((i>>j)&1);
            for(int j=1;j<=m;j++)
            {
                int x = b[j].i,y = b[j].j,bx = b[j].hi,by = b[j].hj;
                if(a[x]==bx)continue;
                if(a[y]==by)ae(gt(x,bx),gt(x,3-bx-a[x]));
                else ae(gt(x,bx),gt(y,by)),ae(gt(y,3-by-a[y]),gt(x,3-bx-a[x]));
            }
            for(int j=2;j<=(n<<1|1);j++)
                if(!dep[j])tarjan(j);
            if(check())
            {
                for(int j=1;j<=n;j++)
                    print(j);
                exit(0);
            }
        }
        printf("-1");
        return 0;
    }
    View Code
  • 相关阅读:
    Q:简单实现URL只能页面跳转,禁止直接访问
    Q:elementUI中tree组件动态展开
    一个切图仔的 JS 笔记
    一个切图仔的HTML笔记
    一个切图仔的 CSS 笔记
    GnuPG使用笔记
    SQL Svr 2012 Enterprise/Always-on节点连接超时导致节点重启——case分享
    网卡配置文件备份在原目录下引起网络配置异常
    python培训
    service脚本的写法
  • 原文地址:https://www.cnblogs.com/LiGuanlin1124/p/10738614.html
Copyright © 2011-2022 走看看