HDU 4115 Eliminate the Conflict(简单2-SAT)

来源:互联网 发布:淘宝休闲外套 编辑:程序博客网 时间:2024/06/07 05:05

题目地址
题意:Bob和Alice玩剪刀石头布,一共要玩n轮,但是Bob要出什么Alice都知道,然后告诉你一些限制格式如下:a b flag,如果flag为0,则Alice第a次和b次出的拳必须相同,如果flag为1,则Alice第a次和b次出的拳必须不相同。问Alice在这些条件下能不能每轮都赢Bob。
思路:其实很简单的就可以想到,因为Alice不能输,所以Alice只有两种选择分别是赢和平局,所以又是一个二判性的问题,解决方法就是2-SAT,所以我们来想怎么建图,因为你已经提前知道了Bob会出什么了,所以我们可以把Ailce平局和赢的情况要出的列出来,然后之后又限制条件的时候看下这个表进行连边就好了。

#include <iostream>#include <cstring>#include <string>#include <queue>#include <vector>#include <map>#include <set>#include <cmath>#include <cstdio>#include <algorithm>#include <iomanip>#define N 100010#define M 1000010//双倍#define LL __int64#define inf 0x3f3f3f3f#define lson l,mid,ans<<1#define rson mid+1,r,ans<<1|1#define getMid (l+r)>>1#define movel ans<<1#define mover ans<<1|1using namespace std;const LL mod = 1000000007;const double eps = 0.001;int n, m;int head[N], idx;struct node {    int to;    int next;}edge[M];int num[N][2];struct two_SAT {    int dfn[N], low[N];    int stack[N], top;    int belong[N], cnt, num;    bool vis[N];    void init() {        memset(head, -1, sizeof(head));        memset(belong, 0, sizeof(belong));        memset(dfn, 0, sizeof(dfn));        memset(vis, false, sizeof(vis));        num = cnt = 0;        top = 0;        idx = 0;    }    void addedge(int a, int b) {        edge[idx].to = b;        edge[idx].next = head[a];        head[a] = idx++;    }    void tarjin(int u) {//缩点        dfn[u] = low[u] = ++num;        vis[u] = true;        stack[top++] = u;        for (int i = head[u]; ~i; i = edge[i].next) {            int v = edge[i].to;            if (!dfn[v]) {                tarjin(v);                low[u] = min(low[u], low[v]);            }            else if (vis[v]) {                low[u] = min(low[u], dfn[v]);            }        }        if (dfn[u] == low[u]) {            while (true) {                int v = stack[--top];                vis[v] = false;                belong[v] = cnt;//标记联通分量belong                 if (u == v) break;            }            cnt++;        }    }    bool two_sat() {        for (int i = 0; i < 2 * n; i++) {//总点数              if (!dfn[i]) tarjin(i);        }        for (int i = 0; i < 2 * n; i += 2) {//遍历是不是会有一个人有2种可能            if (belong[i] == belong[i + 1]) {                return false;            }        }        return true;    }}sat;int main() {    cin.sync_with_stdio(false);    int T, Case = 1;    int a, b, c;    cin >> T;    while (T--){        cin >> n >> m;        sat.init();        for (int i = 1; i <= n; i++) {            cin >> a;            a--;            num[i][0] = a;//平局            num[i][1] = (a + 1) % 3;//赢        }        for (int i = 0; i < m; i++) {            cin >>a >> b >> c;//a*2为平局 a*2+1为赢            if (c) {//Alice第a次和b次出的拳必须不相同                if (num[a][0] == num[b][0]) {//如果第a次想赢要出的和第b次想赢的一样,那就让两个交叉相连                    sat.addedge(a * 2, b * 2 + 1);                    sat.addedge(b * 2, a * 2 + 1);                }                if (num[a][0] == num[b][1]) {//如果第a次想赢要出的和第b次想赢的一样,就直线相连                    sat.addedge(a * 2, b * 2);                    sat.addedge(b * 2 + 1, a * 2 + 1);                }                if (num[a][1] == num[b][0]) {                    sat.addedge(a * 2 + 1, b * 2 + 1);                    sat.addedge(b * 2, a * 2);                }                if (num[a][1] == num[b][1]) {                    sat.addedge(a * 2 + 1, b * 2);                    sat.addedge(b * 2 + 1, a * 2);                }            }            else {//Alice第a次和b次出的拳必须相同                if (num[a][0] != num[b][0]) {                    sat.addedge(a * 2, b * 2 + 1);                    sat.addedge(b * 2, a * 2 + 1);                }                if (num[a][0] != num[b][1]) {                    sat.addedge(a * 2, b * 2);                    sat.addedge(b * 2 + 1, a * 2 + 1);                }                if (num[a][1] != num[b][0]) {                    sat.addedge(a * 2 + 1, b * 2 + 1);                    sat.addedge(b * 2, a * 2);                }                if (num[a][1] != num[b][1]) {                    sat.addedge(a * 2 + 1, b * 2);                    sat.addedge(b * 2 + 1, a * 2);                }            }        }        cout << "Case #" << Case++ << ": ";        if (sat.two_sat()) {            cout << "yes" << endl;        }        else {            cout << "no" << endl;        }    }    return 0;}