poj 1703(並查集 另一種解法)

Find them, Catch them
Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 20517   Accepted: 6071

Description

The police office in Tadu City decides to say ends to the chaos, as launch actions to root up the TWO gangs in the city, Gang Dragon and Gang Snake. However, the police first needs to identify which gang a criminal belongs to. The present question is, given two criminals; do they belong to a same clan? You must give your judgment based on incomplete information. (Since the gangsters are always acting secretly.)

Assume N (N <= 10^5) criminals are currently in Tadu City, numbered from 1 to N. And of course, at least one of them belongs to Gang Dragon, and the same for Gang Snake. You will be given M (M <= 10^5) messages in sequence, which are in the following two kinds: 

1. D [a] [b] 
where [a] and [b] are the numbers of two criminals, and they belong to different gangs. 

2. A [a] [b] 
where [a] and [b] are the numbers of two criminals. This requires you to decide whether a and b belong to a same gang. 

Input

The first line of the input contains a single integer T (1 <= T <= 20), the number of test cases. Then T cases follow. Each test case begins with a line with two integers N and M, followed by M lines each containing one message as described above.

Output

For each message "A [a] [b]" in each case, your program should give the judgment based on the information got before. The answers might be one of "In the same gang.", "In different gangs." and "Not sure yet."

Sample Input

1
5 5
A 1 2
D 1 2
A 1 2
D 2 4
A 1 4

Sample Output

Not sure yet.
In different gangs.
In the same gang.

Source




題目類型:並查集

題目描述:略

題目分析:之前用的那個方法屬於比較巧妙的構造。
這次的方法是,把有關係的人(無論是朋友,或者是敵人)都併到一個集合中。
利用該節點與根節點的關係,來判斷是朋友還是敵人。
這樣,集合合併後。勢必需要維護。有兩種思路。
第一種:合併時,花O(n)的時間複雜度來維護關係。 這種方法會TLE
第二種:舉個例子比較好說。如果合併時,是把roota插到rootb上。那麼此時只維護roota與rootb的關係。
roota中其他的節點等到調用findRoot()方法時纔來維護。


代碼如下:


#include <iostream>
#include <stdio.h>
#define N 100001
using namespace std;

int f[N];
int g[N];
int rank[N];
int n;


void makeSet(){
    for(int i = 1; i <= n; i++){
        f[i] = i;
        g[i] = 0;
        rank[i] = 0;
    }
}

int findRoot(int x){
    if( f[x] == x ){
        return x;
    } else {
        int temp = f[x]; //記錄當前的父節點

        f[x] = findRoot(f[x]); //維護父節點,並壓縮路徑。

        if(temp != f[x]) { //如果剛纔記錄的當前父節點不是根節點,則需要維護。
            if(g[x] == 0){
                g[x] = g[temp];
            } else {
                g[x] = (g[temp] + 1)%2;
            }
        }
        return f[x];
    }
}
void merge(int a,int b){
    int ra = findRoot(a);
    int rb = findRoot(b);

    if(ra != rb){
        if(rank[ra] < rank[rb]) {
            f[ra] = rb;
            g[ra] = ((g[a] + g[b]) + 1)%2; //合併時,因爲曾經的根節點,現在不是根節點了。
                                           //需要維護它與現在根節點的關係。
        } else {
            f[rb] = ra;
            g[rb] = ((g[a] + g[b]) + 1)%2;
            if(rank[ra] == rank[rb]){
                rank[ra]++;
            }
        }
    }
}



int main()
{
    int t;
    scanf("%d",&t);
    while(t--){

        int m;
        scanf("%d%d",&n,&m);
        makeSet();

        char command;
        int a;
        int b;
        for(int i = 0; i < m;i++){
            getchar();
            command = getchar();
            scanf("%d%d",&a,&b);
            if( command == 'A') {
                int ra = findRoot(a);
                int rb = findRoot(b);
                if(ra != rb){
                    printf("Not sure yet.\n");
                } else {
                    if(g[a] == g[b]){
                        printf("In the same gang.\n");
                    } else {
                        printf("In different gangs.\n");
                    }

                }
            } else {
                merge(a,b);
            }
        }
    }
    return 0;
}



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