poj 1703(并查集 另一种解法)

来源:互联网 发布:js制作表格 编辑:程序博客网 时间:2024/06/05 06:12
Find them, Catch them
Time Limit: 1000MS Memory Limit: 10000KTotal 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

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

Sample Output

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

Source

POJ Monthly--2004.07.18



题目类型:并查集

题目描述:略

题目分析:之前用的那个方法属于比较巧妙的构造。
这次的方法是,把有关系的人(无论是朋友,或者是敌人)都并到一个集合中。
利用该节点与根节点的关系,来判断是朋友还是敌人。
这样,集合合并后。势必需要维护。有两种思路。
第一种:合并时,花O(n)的时间复杂度来维护关系。 这种方法会TLE
第二种:举个例子比较好说。如果合并时,是把roota插到rootb上。那么此时只维护roota与rootb的关系。
roota中其他的节点等到调用findRoot()方法时才来维护。


代码如下:


#include <iostream>#include <stdio.h>#define N 100001using 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;}


原创粉丝点击