zoukankan      html  css  js  c++  java
  • POJ

    (点击此处查看原题)

    题意

    有n个变量,编号为0~n-1,每个变量只会取0和1,此时有m对关系:a b c operator ,表示变量a,b满足 a operator b == c ,问对n个变量是否存在一种赋值,使得m对关系全部满足

    解题思路

    由题意就知道,这是一个2-SAT问题,给出了两个变量之间值的关系,相当于给出了推导关系,不过这个地方和常规的关系(如果a为真,那么b为假) 不一样,这里的关系是:a,b 满足 a operator b == c ,所以这个题的难度就在于如何根据形如 a operator b == c 这样的关系找到变量之间的推导关系 ,我们用a表示a取1,用¬a表示a为0

    (加深一下2--SAT问题的处理方法:我们处理2-SAT问题的时候建的由a到¬b的边的关系为:当a为真,推出¬b也为真,也就是 a为真,¬b为真,b为假,所以对于任意变量x,如果存在x和¬x在同一强连通分量内,则无解,个人认为2-SAT问题的核心考点就是提取出变量之间的推导关系,其余的都是板子了)

    下面给出每个关系对应的推导关系:

    1)a AND b == 1 ,此时必须使得a,b同时为1,那么如果出现¬a或者¬b,那么必然是无解,所以建边 a →¬a 和 b  →¬b

    2)a AND b == 0 ,此时我们有很多的可满足关系,但是推导关系只有:a为1,b必定为0 ; b为1,a必定为0,所以建边 a→¬b 和 b →¬a

    3)a OR b == 1,有推导关系:a为0,则b为1;b为0.则a为1,所以建边 ¬a→b 和 ¬b→a 

    4)a OR b == 0,此时必须使得a,b同时为0,那么如果出现a或者b,那么必然是无解,所以建边¬a →a 和 ¬b  →b

    5)a XOR b == 1,此时a和b的值必定不同,所以建边: a→¬b 、 ¬a→b、b →¬a 和¬b→a 

    6)a XOR  b == 0,此时a和b的值必定相同,所以建边:a→b 、 ¬a→¬b、b →a 和¬b→¬a 

    根据以上关系建好图后,就是套用2-SAT的模板求解了

    代码区

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<queue>
    #include<string>
    #include<fstream>
    #include<vector>
    #include<stack>
    #include <map>
    #include <iomanip>
    
    #define bug cout << "**********" << endl
    #define show(x, y) cout<<"["<<x<<","<<y<<"] "
    #define LOCAL = 1;
    using namespace std;
    typedef long long ll;
    const ll inf = 2e9 + 10;
    const ll mod = 1e9 + 7;
    const int Max = 1e4 + 10;
    const int Max2 = 3e2 + 10;
    
    int n, m;
    char order[5];
    vector<int> edge[Max];
    int dfn[Max], low[Max], time_clock;
    int line[Max], now;
    int id[Max], sccCnt;
    
    void init()
    {
        for (int i = 0; i < Max; i++)
            edge[i].clear();
        memset(id, 0, sizeof(id));
        now = sccCnt = 0;
    }
    
    void tarjan(int u)
    {
        dfn[u] = low[u] = ++time_clock;
        line[++now] = u;        //记录访问次序
        for (int i = 0; i < (int) edge[u].size(); i++)
        {
            int v = edge[u][i];
            if (!dfn[v])
            {
                tarjan(v);
                low[u] = min(low[u], low[v]);
            }
            else if (!id[v])        //不属于其他的连通分量,如果属于其他的强连通分量,那就破坏了此时不求强连通分量之间的关系的计划
            {
                low[u] = min(low[u], dfn[v]);
            }
        }
        if (dfn[u] == low[u])        //此时代表从u向下走,又回到了u点,也就是成环了,我们将这一点定义为强连通分量的根结点
        {
            sccCnt++;
            while (line[now] != u)    //同一个强连通分量中的点用同一个数标识
                id[line[now]] = sccCnt, now--;
            id[line[now]] = sccCnt, now--;
        }
    }
    
    
    int main()
    {
    #ifdef LOCAL
    //    freopen("input.txt", "r", stdin);
    //    freopen("output.txt", "w", stdout);
    #endif
        while (scanf("%d%d", &n, &m) != EOF)
        {
            init();
            for (int i = 1, a, b, val; i <= m; i++)
            {
                scanf("%d%d%d%s", &a, &b, &val, order);
                if (order[0] == 'A')
                {
                    if (val == 1)
                        edge[a + n].push_back(a), edge[b + n].push_back(b);        //a,b不可能取0,如果出现,直接当作无解
                    else
                        edge[a].push_back(b + n), edge[b].push_back(a + n);  //a为1,则b为0;b为1,则a为0
                }
                else if (order[0] == 'O')
                {
                    if (val == 1)
                        edge[a + n].push_back(b), edge[b + n].push_back(a);         //a为0,则b为1;b为1,则a为1
                    else
                        edge[a].push_back(a + n), edge[b].push_back(b + n);    //a,b不可能为1,如果出现,直接当作无解
                }
                else
                {
                    if (val == 1)
                        edge[a].push_back(b + n), edge[a + n].push_back(b),
                        edge[b].push_back(a + n), edge[b + n].push_back(a);      //a,b总是不同
                    else
                        edge[a].push_back(b), edge[a + n].push_back(b + n),
                        edge[b].push_back(a), edge[b + n].push_back(a + n);        //a,b总是相同
                }
            }
            for (int i = 0; i < (n << 1); i++)
                if (!dfn[i])
                    tarjan(i);
            bool ok = true;
            for (int i = 0; i < n; i++)
            {
                if (id[i] == id[i + n])
                {
                    ok = false;
                    break;
                }
            }
            if (ok)
                printf("YES
    ");
            else
                printf("NO
    ");
        }
        return 0;
    }
    View Code
  • 相关阅读:
    poj 3278 Catch That Cow(bfs+队列)
    poj 1265 Area(Pick定理)
    poj 2388 Who's in the Middle
    poj 3026 Borg Maze(bfs+prim)
    poj 2485 Highways
    变量引用的错误:UnboundLocalError: local variable 'range' referenced before assignment
    Sysbench硬件基准测试
    Sysbench-OLTP数据库测试
    字典
    操作列表
  • 原文地址:https://www.cnblogs.com/winter-bamboo/p/11406573.html
Copyright © 2011-2022 走看看