• POJ3678 Katu Puzzle


    传送门

    一道非常不错的建图2-SAT。

    首先花了几分钟看懂题……毕竟是英文。然后我们发现其实一共只有六种限制,然后我们的目标就是求出一组布尔方程的解使得整个方程值为真。

    我们进行一下转换:

    1.a&&b=1,这样我们就必须保证a,b同时为真,那就从!a向a建边,!b向b建边。

    2.a&&b=0,这样的话只要a,b不同时为真即可。这个一开始可能不知道该咋连(其实你要是瞎画也能画出来),不过后来发现这其实是a||b的相对情况,所以我们只要将a向!b连边,b向!a连边即可。

    3.a || b = 1.这样只要a,b不同时为假即可,就是!a向b连边,!b向a连边。

    4.a || b = 0,这样两者必须同时为假,与第一种情况相对,从a向!a建边,b向!b建边。

    5.a^b = 1,也就是两者需要不同。我们把他转换成合取范式(这玩意我都忘了自己咋推出来的了),就是(a || b)&&(!a || !b)把两个子句转化一下建边。

    6.a^b=0,两者相同。同样转换为合取范式(与上一种是相对应的),就是(!a || b) && (a || !b) ,把两个子句转化建边。

    这样就建好啦,跑一遍2-SAT求解。

    看一下代码。

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<iostream>
    #include<cmath>
    #include<set>
    #include<queue>
    #define rep(i,a,n) for(int i = a;i <= n;i++)
    #define per(i,n,a) for(int i = n;i >= a;i--)
    #define fill(x,y) memset(x,y,sizeof(x));
    #define enter putchar('
    ')
    
    using namespace std;
    typedef long long ll;
    const int M = 10005;
    const int N = 500005;
    const int INF = 1000000009;
    
    int read()
    {
        int ans = 0,op = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9')
        {
        if(ch == '-') op = -1;
        ch = getchar();
        }
        while(ch >= '0' && ch <= '9')
        {
        ans *= 10;
        ans += ch - '0';
        ch = getchar();
        }
        return ans * op;
    }
    
    struct edge
    {
        int next,from,to;
    }e[N<<2];
    
    int n,m,a,b,c,ecnt,head[M],dfn[M],low[M],stack[M],top,idx,cnt,scc[M];
    bool vis[M];
    char s[10];
    
    void add(int x,int y)
    {
        e[++ecnt].to = y;
        e[ecnt].from = x;
        e[ecnt].next = head[x];
        head[x] = ecnt;
    }
    
    void tarjan(int x)
    {
        dfn[x] = low[x] =++idx;
        vis[x] = 1,stack[++top] = x;
        for(int i = head[x];i;i = e[i].next)
        {
        if(!dfn[e[i].to]) tarjan(e[i].to),low[x] = min(low[x],low[e[i].to]);
        else if(vis[e[i].to]) low[x] = min(low[x],dfn[e[i].to]);
        }
        if(dfn[x] == low[x])
        {
        int p;
        cnt++;
        while((p = stack[top--]))
        {
            scc[p] = cnt,vis[p] = 0;
            if(x == p) break;
        }
        }
    }
    
    int main()
    {
        n = read(),m = read();
        rep(i,1,m)
        {
        a = read(),b = read(),c = read();
        a++,b++;
        scanf("%s",s);
        if(c == 1)
        {
            if(s[0] == 'A') add(a+n,a),add(b+n,b);
            else if(s[0] == 'O') add(a+n,b),add(b+n,a);
            else if(s[0] == 'X') add(a+n,b),add(a,b+n),add(b+n,a),add(b,a+n);
        }
        else if(c == 0)
        {
            if(s[0] == 'A') add(a,b+n),add(b,a+n);
            else if(s[0] == 'O') add(a,a+n),add(b,b+n);
            else if(s[0] == 'X') add(a,b),add(a+n,b+n),add(b+n,a+n),add(b,a);
        }
        }
        rep(i,1,n<<1) if(!dfn[i]) tarjan(i);
        rep(i,1,n) if(scc[i] == scc[i+n]) printf("NO
    "),exit(0);
        printf("YES
    ");
        return 0;
    }
  • 相关阅读:
    最短路计数
    轻拍牛头(类埃式筛)
    子序列(尺取模板题)
    状压dp(洛谷:互不侵犯)
    刷题-力扣-73. 矩阵置零
    刷题-力扣-150. 逆波兰表达式求值
    刷题-力扣-300. 最长递增子序列
    刷题-力扣-1576. 替换所有的问号
    刷题-力扣-54. 螺旋矩阵
    刷题-力扣-705. 设计哈希集合
  • 原文地址:https://www.cnblogs.com/captain1/p/9760902.html
Copyright © 2020-2023  润新知