zoukankan      html  css  js  c++  java
  • luogu 2-SAT 问题

    题目大意:给出n个bool变量,以及m个条件,条件为x,vx,y,vy,表示 x == vx || y == vy 。

    求匹配。

    题解:

    最近新学了一下2-SAT算法。2-SAT指有若干个bool变量(显然有1/0两个值),还给出若干限定条件,比如:

    t1 || t2

    t1 || !t2

    t1 && t2

    t1 && -t2

    等等。

    然后要求找匹配方案。

    首先大家应该听过差分约束,差分约束是用最短路处理数的大小关系等问题。

    而2-SAT就高级多了,他是将关系映射到图上,然后用tarjan等方法判断情况是否存在。

    具体操作是:

    若t1成立则t2一定成立,就从t1向t2连一条边。

    比如本题(t1成立或t2成立):

    ! t1 -> t2

    ! t2 -> t1

    然后看看$i$和$i+n( !i )$是否在一个集里,在的话就不合法。

    最后跑tarjan缩点,按拓扑逆序处理状态。由于tarjan是正向跑的,那就在$bel [ i ]<bel[ n + i ]$时输出1,要么输出0。

    代码:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define N 1000050
    int n,m,hed[2*N],cnt;
    struct EG
    {
        int to,nxt;
    }e[4*N];
    void ae(int f,int t)
    {
        e[++cnt].to = t;
        e[cnt].nxt = hed[f];
        hed[f] = cnt;
    }
    int dep[2*N],low[2*N],tim;
    int s[2*N],tl;
    bool vis[2*N];
    int bel[2*N],bc;
    void tarjan(int u)
    {
        dep[u]=low[u]=++tim;
        s[++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=s[tl--];
                vis[c]=0;
                bel[c]=bc;
            }
        }
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        int x,vx,y,vy;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d%d",&x,&vx,&y,&vy);
            ae(x+vx*n,y+(!vy)*n);
            ae(y+vy*n,x+(!vx)*n);
        }
        for(int i=1;i<=2*n;i++)
            if(!dep[i])
                tarjan(i);
        for(int i=1;i<=n;i++)
        {
            if(bel[i]==bel[i+n])
            {
                printf("IMPOSSIBLE
    ");
                return 0;
            }
        }
        printf("POSSIBLE
    ");
        for(int i=1;i<=n;i++)
        {
            printf("%d ",bel[i]<bel[i+n]);
        }
        printf("
    ");
        return 0;
    }
  • 相关阅读:
    2018年12月29日 Oracle查询性能优化
    B
    A
    洛谷 P2447 [SDOI2010]外星千足虫
    洛谷 P5358 [SDOI2019]快速查询
    欠的题目
    ZJU-ICPC Summer 2020 Contest 8 B-Picnic
    洛谷 P3164 [CQOI2014]和谐矩阵
    K
    J
  • 原文地址:https://www.cnblogs.com/LiGuanlin1124/p/9858764.html
Copyright © 2011-2022 走看看