zoukankan      html  css  js  c++  java
  • POJ 1703 Find them, Catch them(并查集的扩展应用)

    Find them, Catch them
    Time Limit: 1000MS   Memory Limit: 10000K
    Total Submissions: 21755   Accepted: 6471

    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.
    代码一:
    
     1 /* 功能Function Description:     POJ-1703  并查集的应用的扩展
     2    开发环境Environment:          DEV C++ 4.9.9.1
     3    技术特点Technique:
     4    版本Version:
     5    作者Author:                   可笑痴狂
     6    日期Date:                      20120808
     7    备注Notes:
     8   【转】
     9     解析:并查集的题目,并查集的拓展。
    10     一般的思路是先初始化,各个数自成一个组,然后是两个gangs自成一个组,
    11     但由于两个给定元素有三种关系: In the same gang;  In different gangs;  Not sure yet; 
    12     采用此模型的缺点是判断两个元素关系还未确定这种情况比较复杂,故模型需要改进。本题的正确模型是将已经确定关系的元素组成一个集合,
    13     然后利用两个元素的 father是同一个来确定这两个元素之间的关系。father[a]中存放的是a的根结点,rank中存放的是father[a]与a的关系,
    14     0表示两者不在同一个gangs中,1表示两者在同一个gangs中。具体的程序还是沿袭了并查集的Make_Set()、Find_Set()、 Union_Set()
    15     的三步骤。
    16     心得:并查集有三步是必须的:Make_Set()、Find_Set()、Union_Set()。  rank[a]的改变是伴随着father[a]的改变而更新的
    17     (有father改变就有rank改变),要是father改变了,而rank未改变,此时的rank就记录了一个错误的值,father未改变
    18     (即使实际的father已不是现在的值,但只要father未改变,rank 的值就是“正确”的,认识到这点很重要。)
    19 */
    20 
    21 #include<stdio.h>
    22 int father[100005],rank[100005];
    23 
    24 int find(int a)
    25 {
    26     int t;
    27     if(father[a]==a)
    28         return a;
    29 
    30     t=father[a];
    31     father[a]=find(father[a]);
    32     rank[a]=(rank[a]+rank[t]+1)%2;//必须有,更新路径压缩之后a与根结点之间的关系; father改变,rank就必须要跟着改变
    33     
    34     return father[a];
    35 }
    36 
    37 void merge(int a,int b)
    38 {
    39     int fa,fb;
    40     fa=find(a);
    41     fb=find(b);
    42     if(fa!=fb)
    43     {
    44         father[fa]=fb;
    45         rank[fa]=(rank[a]+rank[b])%2;//fa结点以下的结点的rank不需要改,因为在find中会自动更新
    46     }
    47 }
    48 
    49 int main()
    50 {
    51     int T,a,b,m,n,i;
    52     char cmd[2];
    53     scanf("%d",&T);
    54     while(T--)
    55     {
    56         scanf("%d%d",&n,&m);
    57         for(i=1;i<=n;++i)
    58         {
    59             father[i]=i;
    60             rank[i]=1;
    61         }
    62         for(i=0;i<m;++i)
    63         {
    64             scanf("%s%d%d",cmd,&a,&b);
    65             if(cmd[0]=='A')
    66             {
    67                 if(find(a)==find(b))
    68                 {
    69                     //在使用rank之前,已经在用find函数寻找a的时候将a路径上的所有结点的rank值改变过了
    70                     if((rank[a]+rank[b])%2==0)       //a和b与根节点的关系相同---都是0后者都是1,说明是同一个帮派
    71                         printf("In the same gang.\n");
    72                     else
    73                         printf("In different gangs.\n");
    74                 }
    75                 else
    76                     printf("Not sure yet.\n");
    77             }
    78             else
    79                 merge(a,b);
    80         }
    81     }
    82     return 0;
    83 }

     代码二:

     1 //重新做了一遍,又理了理思路 
     2 #include<iostream>
     3 #include<cstdio>
     4 using namespace std;
     5 
     6 int father[100005],relation[100005];
     7 
     8 void init(int n);
     9 int find(int x);
    10 
    11 int main()
    12 {
    13     int T,N,M,x,y,fx,fy,r1,r2;
    14     char w[3];
    15     scanf("%d", &T);
    16     while(T--)
    17     {
    18         scanf("%d%d", &N, &M);
    19         init(N);
    20         while(M--)
    21         {
    22             scanf("%s%d%d", w, &x, &y);
    23             fx=find(x);
    24             fy=find(y);
    25             if(w[0]=='D')
    26             {
    27                 if(fx != fy)
    28                 {
    29                     father[fx]=fy;
    30                     //相当于已知 a 与 b 的关系(relation[x]),已知 c与 d 的关系(relation[y]),已知 b 与 c 的关系(1),求 a 与 d 的关系 
    31                     relation[fx]=(relation[x]+relation[y]+1)%2;
    32                 }
    33             }
    34             else
    35             {
    36                 if(fx!=fy)
    37                     printf("Not sure yet.\n");
    38                 else
    39                 {
    40                     if(relation[x]!=relation[y])
    41                         printf("In different gangs.\n");
    42                     else
    43                         printf("In the same gang.\n");
    44                 }
    45             }
    46         }
    47     }
    48     return 0;
    49 }
    50 void init(int n)
    51 {
    52     int i;
    53     for(i=0;i<=n;++i)
    54     {
    55         father[i]=i;
    56         relation[i]=0;
    57     }
    58 }
    59 int find(int x)
    60 {
    61     if(x==father[x])
    62     {
    63         return x;
    64     }
    65     else
    66     {
    67         int t=father[x];
    68         father[x]=find(father[x]);
    69         
    70         //相当于已知 a 与 b 的关系,已知 b 与 c 的关系,求 a 与 c 的关系 
    71         relation[x]=(relation[x]+relation[t])%2;//(注意顺序,只有当前节点的父亲节点与根节点的关系确定了才能正确确定)
    72         return father[x];                         //当前节点与根节点的关系所以这条语句一定不能放在上一条语句的上边 
    73     }
    74 }
    功不成,身已退
  • 相关阅读:
    如何快速提高编程能力
    Django线上部署实战教程之Nginx+Gunicorn+Django篇
    Navicat for MySQL远程连接报10038的错误
    DjangoBlog部署教程
    用windows下的Anaconda搭建Django虚拟环境
    基础类型及相关操作
    格式化输出编码问题!
    初识python!
    Java学习之多线程二
    Java学习之多线程一
  • 原文地址:https://www.cnblogs.com/dongsheng/p/2627865.html
Copyright © 2011-2022 走看看