您的位置:首页 > 其它

hdoj 4115 Eliminate the Conflict 【2-sat 经典建图】

2015-07-31 17:22 288 查看

Eliminate the Conflict

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 1918 Accepted Submission(s): 827

Problem Description
Conflicts are everywhere in the world, from the young to the elderly, from families to countries. Conflicts cause quarrels, fights or even wars. How wonderful the world will be if all conflicts can be eliminated.

Edward contributes his lifetime to invent a 'Conflict Resolution Terminal' and he has finally succeeded. This magic item has the ability to eliminate all the conflicts. It works like this:

If any two people have conflict, they should simply put their hands into the 'Conflict Resolution Terminal' (which is simply a plastic tube). Then they play 'Rock, Paper and Scissors' in it. After they have decided what they will play, the tube should be opened
and no one will have the chance to change. Finally, the winner have the right to rule and the loser should obey it. Conflict Eliminated!

But the game is not that fair, because people may be following some patterns when they play, and if the pattern is founded by others, the others will win definitely.

Alice and Bob always have conflicts with each other so they use the 'Conflict Resolution Terminal' a lot. Sadly for Bob, Alice found his pattern and can predict how Bob plays precisely. She is very kind that doesn't want to take advantage of that. So she tells
Bob about it and they come up with a new way of eliminate the conflict:

They will play the 'Rock, Paper and Scissors' for N round. Bob will set up some restricts on Alice.

But the restrict can only be in the form of "you must play the same (or different) on the ith and jth rounds". If Alice loses in any round or break any of the rules she loses, otherwise she wins.

Will Alice have a chance to win?


Input
The first line contains an integer T(1 <= T <= 50), indicating the number of test cases.

Each test case contains several lines.

The first line contains two integers N,M(1 <= N <= 10000, 1 <= M <= 10000), representing how many round they will play and how many restricts are there for Alice.

The next line contains N integers B1,B2, ...,BN, where Bi represents what item Bob will play in the ith round. 1 represents Rock, 2 represents Paper, 3 represents Scissors.

The following M lines each contains three integers A,B,K(1 <= A,B <= N,K = 0 or 1) represent a restrict for Alice. If K equals 0, Alice must play the same on Ath and Bth round. If K equals 1, she must play different items on Ath and Bthround.


Output
For each test case in the input, print one line: "Case #X: Y", where X is the test case number (starting with 1) and Y is "yes" or "no" represents whether Alice has a chance to win.


Sample Input
2
3 3
1 1 1
1 2 1
1 3 1
2 3 1
5 5
1 2 3 2 1
1 2 1
1 3 1
1 4 1
1 5 1
2 3 0




Sample Output
Case #1: no
Case #2: yes
Hint
'Rock, Paper and Scissors' is a game which played by two person. They should play Rock, Paper or Scissors by their hands at the same time. 
Rock defeats scissors, scissors defeats paper and paper defeats rock. If two people play the same item, the game is tied..




题意:A和B两个人要用 N局“石头布剪刀”的游戏来决定胜负,现在给出A在每一轮游戏选择的手势(1表示石头,2表示布,3表示剪刀)。另外A给B设置了M个如a b k的限制,当k = 0时,要求B在第a局游戏和第b局游戏出的手势必须一样;当 k = 1时,要求B在第a局游戏和第b局游戏出的手势不能一样。对于B来说,输掉任意一局 或者 违反规则都是他输,反之他赢。这也就意味着在A和B全平局(每局出的手势一样)的情况下,是B赢。问你B有没有机会获胜。

思路:把每第i局分成6个点,分别表示第i局可能出现的6种状态。

i 表示 出了石头, i + N表示出布, i + 2 *N表示出剪刀,i + 3 * N表示不出石头, i + 4 * N表示不出布, i + 5 * N 表示不出剪刀。

建图:

一:A每一局不能输给B

1,B出石头

addEdge(i + 4 * N, i);//不出布 就必须出石头

addEdge(i + 3 * N, i + N);//不出石头 就必须出布

2,B出布

addEdge(i + 5 * N, i + N);//不出剪刀 就必须出布

addEdge(i + 4 * N, i + 2 * N);//不出布 就必须出剪刀

3,B出剪刀

addEdge(i + 3 * N, i + 2 * N);//不出石头 就必须出剪刀

addEdge(i + 5 * N, i);//不出剪刀 就必须出石头

二:每局只能出现一种状态

1,出了石头就不能出其他的
addEdge(i, i + 4 * N);

addEdge(i, i + 5 * N);

2,出了布 就不能出其他的

addEdge(i + N, i + 3 * N);

addEdge(i + N, i + 5 * N);

3,出了剪刀 就不能出其他的

addEdge(i + 2 * N, i + 3 * N);

addEdge(i + 2 * N, i + 4 * N);

三:根据M个限制

1,a局和b局不能出同一个手势

addEdge(a, b + 3 * N);//a局出石头 b局一定不能出石头

addEdge(b, a + 3 * N);//b局出石头 a局一定不能出石头

addEdge(a + N, b + 4 * N);//a局出布 b局一定不能出布

addEdge(b + N, a + 4 * N);//a局出布 b局一定不能出布

addEdge(a + 2 * N, b + 5 * N);//a局出剪刀 b局一定不能出剪刀

addEdge(b + 2 * N, a + 5 * N);//b局出剪刀 a局一定不能出剪刀

2,a局和b局手势一样

addEdge(a, b);//a局出石头 b局也出石头

addEdge(b, a);//b局出石头 a局也出石头

addEdge(a + N, b + N);//a局出布 b局也出布

addEdge(b + N, a + N);//b局出布 a局也出布

addEdge(a + 2 * N, b + 2 * N);//a局出剪刀 b局也出剪刀

addEdge(b + 2 * N, a + 2 * N);//b局出剪刀 a局也出剪刀

然后tarjan求SCC,判断是否矛盾即可。

AC代码:

#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#include <stack>
#include <algorithm>
#define MAXN 60000+100
#define MAXM 200000+10
#define INF 100000000
using namespace std;
struct Edge
{
    int from, to, next;
};
Edge edge[MAXM];
int head[MAXN], edgenum;
int low[MAXN], dfn[MAXN];
int dfs_clock;
int sccno[MAXN], scc_cnt;
stack<int> S;
bool Instack[MAXN];
int N, M;//N局游戏 M个限制
int TT = 1;
void init()
{
    edgenum = 0;
    memset(head, -1, sizeof(head));
}
void addEdge(int u, int v)
{
    Edge E = {u, v, head[u]};
    edge[edgenum] = E;
    head[u] = edgenum++;
}
void getMap()
{
    int a, b, k;
    for(int i = 1; i <= N; i++)
    {
        scanf("%d", &k);
        switch(k)
        {
            //对手出石头
            case 1: //在第i局出布 或者 出石头
                addEdge(i + 4 * N, i);//不出布 就必须出石头
                addEdge(i + 3 * N, i + N);//不出石头 就必须出布
                break;
            //对手出布
            case 2: //在第i局出剪刀 或者 出布
                addEdge(i + 5 * N, i + N);//不出剪刀 就必须出布
                addEdge(i + 4 * N, i + 2 * N);//不出布 就必须出剪刀
                break;
            //对手出剪刀
            case 3: //在第i局出石头 或者 出剪刀
                addEdge(i + 3 * N, i + 2 * N);//不出石头 就必须出剪刀
                addEdge(i + 5 * N, i);//不出剪刀 就必须出石头
                break;
        }
    }
    //每局只能出一个
    for(int i = 1; i <= N; i++)
    {
        //出了石头就不能出其他的
        addEdge(i, i + 4 * N);
        addEdge(i, i + 5 * N);
        //出了布 就不能出其他的
        addEdge(i + N, i + 3 * N);
        addEdge(i + N, i + 5 * N);
        //出了剪刀 就不能出其他的
        addEdge(i + 2 * N, i + 3 * N);
        addEdge(i + 2 * N, i + 4 * N);
    }
    while(M--)
    {
        scanf("%d%d%d", &a, &b, &k);
        if(k == 1)//a局和b局不同
        {
            addEdge(a, b + 3 * N);//a局出石头 b局一定不能出石头
            addEdge(b, a + 3 * N);//b局出石头 a局一定不能出石头
            addEdge(a + N, b + 4 * N);//a局出布 b局一定不能出布
            addEdge(b + N, a + 4 * N);//a局出布 b局一定不能出布
            addEdge(a + 2 * N, b + 5 * N);//a局出剪刀 b局一定不能出剪刀
            addEdge(b + 2 * N, a + 5 * N);//b局出剪刀 a局一定不能出剪刀
        }
        else//a局和b局一样
        {
            addEdge(a, b);//a局出石头 b局也出石头
            addEdge(b, a);//b局出石头 a局也出石头
            addEdge(a + N, b + N);//a局出布 b局也出布
            addEdge(b + N, a + N);//b局出布 a局也出布
            addEdge(a + 2 * N, b + 2 * N);//a局出剪刀 b局也出剪刀
            addEdge(b + 2 * N, a + 2 * N);//b局出剪刀 a局也出剪刀
        }
    }
}
void tarjan(int u, int fa)
{
    int v;
    low[u] = dfn[u] = ++dfs_clock;
    S.push(u);
    Instack[u] = true;
    for(int i = head[u]; i != -1; i = edge[i].next)
    {
        v = edge[i].to;
        if(!dfn[v])
        {
            tarjan(v, u);
            low[u] = min(low[u], low[v]);
        }
        else if(Instack[v])
            low[u] = min(low[u], dfn[v]);
    }
    if(low[u] == dfn[u])
    {
        scc_cnt++;
        for(;;)
        {
            v = S.top(); S.pop();
            Instack[v] = false;
            sccno[v] = scc_cnt;
            if(v == u) break;
        }
    }
}
void find_cut(int l, int r)
{
    memset(low, 0, sizeof(low));
    memset(dfn, 0, sizeof(dfn));
    memset(sccno, 0, sizeof(sccno));
    memset(Instack, false, sizeof(Instack));
    dfs_clock = scc_cnt = 0;
    for(int i = l; i <= r; i++)
        if(!dfn[i]) tarjan(i, -1);
}
void solve()
{
    printf("Case #%d: ", TT++);
    for(int i = 1; i <= 3 * N; i++)
    {
        if(sccno[i] == sccno[i + 3 * N])
        {
            printf("no\n");
            return ;
        }
    }
    printf("yes\n");
}
int main()
{
    int t;
    scanf("%d", &t);
    while(t--)
    {
        scanf("%d%d", &N, &M);
        init();
        getMap();
        find_cut(1, 6 * N);
        solve();
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: