• [NOI2017]游戏——2-sat


    题面

      Bzoj4945

    解析

       一道非常有趣的2-sat题

      一开始我就想偏了,我想给每一张地图建3个点分别代表A, B, C车,然后发现不会连边(就是菜到没看出来这道题怎么用2-sat),于是看了看思路,自己把代码搞出来,细细想来这个题还是很巧妙的

      假如每一张地图建3个点,由于 d<=8 , 近$frac{1}{3}$的点会浪费,因此我们删去不能选的点,绝大部分地图都只有两个点了。这时先不考虑存在x的情况,于是所有地图就只有2个点,在2个点中选一个作为地图的选择,会有许多限制关系,那么很明显的2-sat了。考虑如何对题目中的四元组$(i, h_{i}, j, h_{j})$连边, 当然是分情况讨论,假设点$i$代表$h_{i}$, 点$i'$是点$i$的镜像点,点$j$与点$j'$同理, 如果$i$号点恰好不能选$h_{i}$,那就不连边;如果$i$号点可以选$h_{i}$但$j$号点不能选$h_{j}$, 那么强制让$i$号点选择除$h_{i}$以外的那个点,即$i ightarrow i'$;如果$i$号点可以选$h_{i}$并且$j$号点可以选$h_{j}$,那么$i ightarrow j$,$j' ightarrow i'$(逆否命题)。至此建图结束,剩下的就是tarjan了,分类讨论的部分可以结合下面的代码看看,我写在了work函数内

      然后就是存在x的情况了,d很小,考虑暴力枚举每一张x图的车,我们已经建好了一张地图两辆车的2-sat的图,那么枚举每一张x图时要选出2辆车,由于x图是在3辆车中选一辆车,因此每一张x图有两种选法才能覆盖到跑x图的3种车,我是用的(A, C),与(B, C), 这样就没有遗漏的枚举出x图的情况了。枚举的时间是$2^{d}$ ,每一次重新建图,跑tarjan,因此总时间复杂度是$O(2^{d}(n+m))$

      Special Judge的存在所以我没过样例还是AC了

     代码:

    #include<cstdio>
    #include<iostream>
    #include<vector>
    #include<algorithm>
    using namespace std;
    const int maxn = 50004;
    
    template<class T>
    inline void read(T &re)
    {
        T fl = 1;char c;
        while((c=getchar())&&(c<'0'||c>'9'))if(c=='-')fl=-1;
        re=c-'0';
        while((c=getchar())&&(c>='0'&&c<='9'))re=(re<<3)+(re<<1)+c-'0';
        re*=fl;
    }
    
    int n, m, d, rel[2][maxn];//A:1, B:2, C:3
    char s[maxn];
    
    int cnt, timer, top, stak[maxn<<1], dfn[maxn<<1], low[maxn<<1], bel[maxn<<1], xpos[10];
    bool vis[maxn<<1];
    vector<int> G[maxn<<1];
    
    struct requir{
        int a, b;
        char ca, cb;
    }req[maxn<<1];
    
    void tarjan(int x)
    {
        low[x] = dfn[x] = ++timer;
        stak[++top] = x;
        vis[x] = 1;
        for(unsigned int i = 0; i < G[x].size(); ++i)
        {
            int id = G[x][i];
            if(!dfn[id])
            {
                tarjan(id);
                low[x] = min(low[x], low[id]);
            }
            else if(vis[id])
                low[x] = min(low[x], dfn[id]);
        }
        if(dfn[x] == low[x])
        {
            cnt++;
            int t;
            do
            {
                t = stak[top--];
                vis[t] = 0;
                bel[t] = cnt;
            }
            while(t != x);
        }
    }
    
    bool work()
    {
        timer = cnt = 0;
        for(int i = 1; i <= (n<<1); ++i)
        {
            bel[i] = dfn[i] = low[i] = 0;
            G[i].clear();
        }
        for(int i = 1; i <= m; ++i)
        {
            if(s[req[i].a] == req[i].ca)
                continue;
            if(s[req[i].b] == req[i].cb)
            {
                int x = (rel[1][req[i].a] + 'a' - 1 == req[i].ca);
                if(x == 1)
                    G[req[i].a+n].push_back(req[i].a);
                else
                    G[req[i].a].push_back(req[i].a+n);
            }
            else
            {
                int x = (rel[1][req[i].a] + 'a' - 1 == req[i].ca);
                int y = (rel[1][req[i].b] + 'a' - 1 == req[i].cb);
                if(x == 1)
                {
                    if(y == 1)
                    {
                        G[req[i].a+n].push_back(req[i].b+n);
                        G[req[i].b].push_back(req[i].a);
                    }
                    else
                    {
                        G[req[i].a+n].push_back(req[i].b);
                        G[req[i].b+n].push_back(req[i].a);    
                    }
                }
                else
                {
                    if(y == 1)
                    {
                        G[req[i].a].push_back(req[i].b+n);
                        G[req[i].b].push_back(req[i].a+n);
                    }
                    else
                    {
                        G[req[i].a].push_back(req[i].b);
                        G[req[i].b+n].push_back(req[i].a+n);    
                    }
                }
            }
        }
        for(int i = 1; i <= (n<<1); ++i)
            if(!dfn[i])
                tarjan(i);
        for(int i = 1; i <= n; ++i)
            if(bel[i] == bel[i+n])
                return 0;
        return 1;
    }
    
    void dfs(int x)
    {
        if(x > d)
        {
            bool fl = work();
            if(fl)
            {
                for(int i = 1; i <= n; ++i)
                    printf("%c", rel[bel[i] > bel[i+n]][i] + 'A' - 1);
                exit(0);
            }
            else 
                return;
        }
        for(int i = 1; i <= 2; ++i)
        {
            rel[0][xpos[x]] = 3 - i;
            rel[1][xpos[x]] = 3;
            s[xpos[x]] = 'a' + i - 1;
            dfs(x+1);
        }
    }
    
    int main()
    {
        read(n);read(d);
        scanf("%s", s+1);
        d = 0;
        for(int i = 1; i <= n; ++i)
        {
            if(s[i] == 'x')
                xpos[++d] = i;
            else if(s[i] == 'a')
            {
                rel[0][i] = 2;
                rel[1][i] = 3;
            }
            else if(s[i] == 'b')
            {
                rel[0][i] = 1;
                rel[1][i] = 3;
            }
            else
            {
                rel[0][i] = 1;
                rel[1][i] = 2;
            }
        }
        read(m);
        for(int i = 1; i <= m; ++i)
        {
            char ch[4];
            read(req[i].a);
            scanf("%s", ch);
            req[i].ca = ch[0] - 'A' + 'a';
            read(req[i].b);
            scanf("%s", ch);
            req[i].cb = ch[0] - 'A' + 'a';
        }
        dfs(1);
        printf("-1");
        return 0;
    }
    View Code
  • 相关阅读:
    Linux防火墙使用配置
    es安装笔记
    git仓库免密码登陆配置
    swgger前后端分离api生成
    关于redis
    学习笔记关于springboot
    idea 安装记录
    随记
    开课吧--Python数据分析--第4节 数据七十二变--互动练习:如果你不需要,就让它消失!
    jupyter使用方法
  • 原文地址:https://www.cnblogs.com/Joker-Yza/p/11318789.html
Copyright © 2020-2023  润新知