hdu4115 Eliminate the Conflict

題意:對,又是Alice和Bob玩起了石頭剪刀布。Alice知道Bob每回合要出什麼,現在對於Alice 有m個限制,每個限制由a,b,k三個數字來描述。

k == 0,則第a局和第b局 Alice出的相同。

k==1,則代表第a局和第b局Alice出的必須不同。

求是否存在可以使得Alice每局不輸(平或勝)且符合以上m個要求的方案。


石頭剪刀布,看似有三種選擇,但是仔細分析發現,由於Bob出什麼已定,那麼對於Alice來說只有選擇平或勝兩種選擇,那麼可以聯想至Twosat

根據這些限制建圖,twosat求解即可


#include <cstdio>
#include <ctime>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <string>
#include <set>
#include <stack>
#include <map>
#include <cmath>
#include <vector>
#include <iostream>
#include <algorithm>
#include <bitset>
#include <fstream>
#include <sstream>
using namespace std;
//LOOP
#define FF(i, a, b) for(int i = (a); i < (b); ++i)
#define FE(i, a, b) for(int i = (a); i <= (b); ++i)
#define FED(i, b, a) for(int i = (b); i>= (a); --i)
#define REP(i, N) for(int i = 0; i < (N); ++i)
#define CLR(A,value) memset(A,value,sizeof(A))
//OTHER
#define SZ(V) (int)V.size()
#define PB push_back
#define MP make_pair
#define all(x) (x).begin(),(x).end()
#define EQ(a, b) (fabs((a) - (b)) <= 1e-10)
//INPUT
#define RI(n) scanf("%d", &n)
#define RII(n, m) scanf("%d%d", &n, &m)
#define RIII(n, m, k) scanf("%d%d%d", &n, &m, &k)
#define RS(s) scanf("%s", s)
//OUTPUT
#define WI(n) printf("%d\n", n)
#define WS(n) printf("%s\n", n)

typedef long long LL;
typedef unsigned long long ULL;
typedef vector <int> VI;
const int INF = 1000000000;
const double eps = 1e-10;
const int MOD = 1000000000;
const int maxn = 10010;

struct TwoSat{
    int n;
    VI G[maxn * 2];
    bool mark[maxn * 2];
    int S[maxn * 2], c;

    bool dfs(int x)
    {
        if (mark[x ^ 1]) return 0;
        if (mark[x]) return 1;
        mark[x] = 1;
        S[c++] = x;
        REP(i, G[x].size())
            if (!dfs(G[x][i])) return 0;
        return 1;
    }

    void init(int n)
    {
        this -> n = n;
        REP(i, n * 2) G[i].clear();
        CLR(mark, 0);
    }

    void add_clause(int x, int xval, int y, int yval)          ///x = xval 或 y = yval
    {
        x = x * 2 + xval, y = y * 2 + yval;
        G[x ^ 1].PB(y), G[y ^ 1].PB(x);
    }

    bool solve()
    {
        for (int i = 0; i < n * 2; i += 2)
        {
            if (!mark[i] && !mark[i + 1])
            {
                c = 0;
                if (!dfs(i))
                {
                    while (c > 0) mark[S[--c]] = 0;
                    if (!dfs(i + 1)) return 0;
                }
            }
        }
        return 1;
    }
}sat;
int op[maxn];      ///Bob每局出什麼,1 represents Rock, 2 represents Paper, 3 represents Scissors


int main()
{
    int N, T, M;
    int fir, sec, k;
    RI(T);
    FE(kase, 1, T)
    {
        RII(N, M);
        sat.init(N);
        FF(i, 0, N)
            RI(op[i]);
        REP(i, M)
        {
            RIII(fir, sec, k);
            fir--, sec--;
            if (op[fir] == op[sec])     ///如果這兩局Bob出的相同
            {
                if (k == 1)              
                    sat.add_clause(fir, 1, sec, 1), sat.add_clause(fir, 0, sec, 0);     ///兩次不能相同
                else
                    sat.add_clause(fir, 0, sec, 1), sat.add_clause(fir, 1, sec, 0);      ///兩次必須相同
            }
            else if ((op[sec] == 1 && op[fir] == 3) || (op[fir] == 1 && op[sec] == 2) || (op[fir] == 2 && op[sec] == 3)) /// fir局出的輸給sec局
            {
                if (k == 1)
                    sat.add_clause(fir, 0, sec, 1);
                else
                    sat.add_clause(fir, 1, fir, 1), sat.add_clause(sec, 0, sec, 0);
            }
            else
            {
                if (k == 1)
                    sat.add_clause(fir, 1, sec, 0);
                else
                    sat.add_clause(fir, 0, fir, 0), sat.add_clause(sec, 1, sec, 1);
            }
        }
        printf("Case #%d: ", kase);
        bool f = sat.solve();
        if (f)
            puts("yes");
        else
            puts("no");
    }
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章