1. 程式人生 > >UVA10158 War【並查集】

UVA10158 War【並查集】

A war is being lead between two countries, A and B. As a loyal citizen of C, you decide to help your countrys espionage by attending the peace-talks taking place these days (incognito, of course). There are n people at the talks (not including you), but you do not know which person belongs to which country. You can see people talking to each other, and through observing their behaviour during their occasional one-to-one conversations, you can guess if they are friends or enemies. In fact what your country would need to know is whether certain pairs of people are from the same country, or they are enemies. You may receive such questions from Cs government even during the peace-talks, and you have to give replies on the basis of your observations so far. Fortunately nobody talks to you, as nobody pays attention to your humble appearance.

  Now, more formally, consider a black box with the following operations:

        setFriends(x,y) shows that x and y are from the same country

        setEnemies(x,y) shows that x and y are from different countries

        areFriends(x,y) returns true if you are sure that x and y are friends

        areEnemies(x,y) returns true if you are sure that x and y are enemies

  The first two operations should signal an error if they contradict with your former knowledge. The two relations ‘friends’ (denoted by ∼) and ‘enemies’ (denoted by ∗) have the following properties:

∼ is an equivalence relation, i.e.

        1. If x ∼ y and y ∼ z then x ∼ z (The friends of my friends are my friends as well.

        2. If x ∼ y then y ∼ x (Friendship is mutual.)

        3. x ∼ x (Everyone is a friend of himself.)

∗ is symmetric and irreflexive

        1. If x ∗ y then y ∗ x (Hatred is mutual.)

        2. Not x ∗ x (Nobody is an enemy of himself.)

Also

        1. If x ∗ y and y ∗ z then x ∼ z (A common enemy makes two people friends.

        2. If x ∼ y and y ∗ z then x ∗ z (An enemy of a friend is an enemy.

  Operations setFriends(x,y) and setEnemies(x,y) must preserve these properties.

Input

The first line contains a single integer, n, the number of people.

  Each of the following lines contains a triple of integers, cxy, where c is the code of the operation:

        c = 1, setFriends

        c = 2, setEnemies

        c = 3, areFriends

        c = 4, areEnemies

and x and y are its parameters, which are integers in the range [0, n), identifying two (different) people. The last line contains ‘0 0 0’.

  All integers in the input file are separated by at least one space or line break. The only constraint is n < 10000, the number of operations is unconstrained.

Output

For every “areFriends” and “areEnemies” operation write ‘0’ (meaning no) or ‘1’ (meaning yes) to the output. Also for every “setFriends” or “setEnemies” operation which contradicts with previous knowledge, output a ‘-1’ to the output; note that such an operation should produce no other effect and execution should continue. A successful “setFriends” or “setEnemies” gives no output.

  All integers in the output file must be separated by one line break.

Sample Input

10

1 0 1

1 1 2

2 0 5

3 0 2

3 8 9

4 1 5

4 1 2

4 8 9

1 8 9

1 5 2

3 5 2

0 0 0

Sample Output

1

0

1

0

0

-1

0

問題簡述:(略)

問題分析

  這是一個用並查集來解的問題,略為不同於標準的並查集問題。  

  這個問題的關鍵是朋友圈與敵人圈沒有交集。

  總共有n個人,每個人分為自身(1到n)和分身(n+1到2n)兩個圈子,自身加入朋友圈,分身加入敵人圈。

  有四種操作,分別用對應函式來處理。

程式說明:(略)

題記:(略)

參考連結:(略)

AC的C++語言程式如下:

/* UVA10158 War */

#include <bits/stdc++.h>

using namespace std;

const int N = 10000;
int f[N * 2  + 1], board;

int Find(int a)
{
    for(;;) {
        if(f[a] != a)
            a = f[a];
        else
            return a;
    }
}

void setFriend( int a, int b )
{
    int x1, x2, y1, y2;
    x1 = Find(a);
    y1 = Find(b);
    x2 = Find(a + board);
    y2 = Find(b + board);
    if ( x1 == y2 || x2 == y1 )
        printf("-1\n");
    else {
        f[x1] = y1;
        f[x2] = y2;
    }
}

void setEnemy( int a, int b )
{
    int x1, x2, y1, y2;
    x1 = Find(a);
    y1 = Find(b);
    x2 = Find(a + board);
    y2 = Find(b + board);
    if ( x1 == y1 )
        printf("-1\n");
    else {
        f[x1] = y2;
        f[y1] = x2;
    }
}

void areFriend( int a, int b )
{
    int x, y;
    x = Find(a);
    y = Find(b);

    printf("%d\n", x == y);
}

void areEnemy( int a, int b )
{
    int x1, x2, y1, y2;
    x1 = Find(a);
    y1 = Find(b);
    x2 = Find(a+board);
    y2 = Find(b+board);

    printf("%d\n", x2 == y1 || x1 == y2);
}

int main()
{
    while(~scanf("%d", &board)) {
        int c, x, y;

        // Init Union-Find
        for(int i = 0; i <= board * 2; i++)
            f[i] = i;

        for(;;) {
            scanf("%d%d%d", &c, &x, &y);
            if(c == 0 && x == 0 && y == 0)
                break;

            if ( c == 1 )
                setFriend( x, y );
            else if ( c == 2 )
                setEnemy( x, y );
            else if ( c == 3 )
                areFriend( x, y );
            else if ( c == 4 )
                areEnemy( x, y );
        }
    }

    return 0;
}