POJ 1703 -- Find them, Catch them


http://poj.org/problem?id=1703
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.
http://blog.csdn.net/freezhanacmore/article/details/8774033
题意 :有两个不同的帮派,每个帮派至少有一个人。 判断两个人是否属于同一个帮派。
              有 T 组测试数据。
              给你 N 个人,编号从 1 到 N,操作 M 次。
              每次操作输入一个字符和两个数 x ,y 
              如果字符为 A 则判断 x 和 y 是否属于同一个帮派,并且输出结果。
              如果字符为 D 则明确告诉你 x 和 y 是属于不同帮派的。
算法:经典并查集的应用。
PS:以前接触的并查集都是让我们判断是否属于同一个连通分量,但这道题却让你判断是否属于同一类。
        开始小纠结了下,如果我昨天没有纠结清楚 POJ 1182 食物链 那题想必肯定是做不出来的,其实想清楚了,这道题就是 食物链 
        那题的简单版本。大笑
思路:除了像普通的并查集定义一个 p[] 记录父亲节点外,还定义一个 r[] 记录当前点与其所属的连通分量的根节点的关系。
            r[] = 0 表示属于同一个帮派; r[] = 1表示与其根节点属于不同的帮派。
            
           开始时初始化自己是自己的父亲 p[x] = x,自己与自己属于同一类 r[x] = 0.
           一旦输入 D 断定 x 和 y 属于不同集合后,就连接 x 和 y 所在的树,同时更新 r[]
           一旦输入 A
           如果 find(x) 不等于 find(y) 说明还没有判断过 x 与 y 直接输出关系不确定即可
      Not sure yet.
      如果find(x)等于 find(y) ,但是他们的r不等,说明属于不同帮派,输出In different gangs.
                               如果他们的r相等,说明属于同一个帮派,则输出In the same gang

注意:1.find()函数寻找根节点的时候要不断的更新 r  
       根据子节点与父亲节点的关系和父节点与爷爷节点的关系,推导子节点与爷爷节点的关系
       如果 a 和 b 的关系是 r1, b 和 c 的关系是 r2,
       那么 a 和 c 的关系就是 (r1+r2)%2 . PS:因为只用两种情况所以对 2 取模。
       如果实在不好理解,那么我们就枚举推理一下,共有 2*2 = 4种情况:
       (a, b) (b, c)  (a, c)  (r1+r2)%2
          0  0       0        0        a 和 b是同类 , b 和 c 是同类, 所以 a 和 c 也是同类
          0      1       1        1        a 和 b是同类 , b 和 c 是异类, 所以 a 和 c 也是异类
          1      0       1        1        a 和 b是异类 , b 和 c 是同类, 所以 a 和 c 是异类
          1      1       0        0        a 和 b是异类 , b 和 c 是异类, 所以 a 和 c 是同类
     2.Union()联合两棵树的时候也要更新两棵树的根的关系
       定义:fx 为 x的根节点, fy 为 y 的根节点
       联合时,使得 p[fx] = fy; 同时也要寻找 fx 与 fy 的关系。关系为:(r[x]+r[y]+1)%2
       如何证明?
       fx 与 x 的关系是 r[x], 
       x 与 y 的关系是 1 (因为确定是不同类,才联合的), 
       y 与 fy 关系是 r[y],模 2 是因为只有两种关系
       所以又上面的一点所推出的定理可以证明 fx 与 fy 的关系是: (r[x]+r[y]+1)%2
  1. const int maxn = 100000+10;  
  2. int p[maxn]; //存父亲节点  
  3. int r[maxn]; //存与根节点的关系,0 代表同类, 1代表不同类  
  4. int find(int x) //找根节点  
  5. {  
  6.     if(x == p[x]) return x;  
  7.     int t = p[x]; //记录父亲节点 方便下面更新r[]  
  8.     p[x] = find(p[x]);  
  9.     r[x] = (r[x]+r[t])%2; //根据子节点与父亲节点的关系和父节点与爷爷节点的关系,推导子节点与爷爷节点的关系  
  10.     return p[x]; //容易忘记  
  11. }  
  12. void Union(int x, int y)  
  13. {  
  14.     int fx = find(x); //x所在集合的根节点  
  15.     int fy = find(y);  
  16.     p[fx] = fy; //合并  
  17.     r[fx] = (r[x]+1+r[y])%2; //fx与x关系 + x与y的关系 + y与fy的关系 = fx与fy的关系  
  18. }  
  19. void set(int n)  
  20. {  
  21.     for(int x = 1; x <= n; x++)  
  22.     {  
  23.         p[x] = x; //自己是自己的父节点  
  24.         r[x] = 0; //自己和自己属于同一类  
  25.     }  
  26. }  
  27. int main()  
  28. {  
  29.     int T;  
  30.     int n, m;  
  31.     scanf("%d", &T);  
  32.     while(T--)  
  33.     {  
  34.         scanf("%d%d%*c", &n, &m);  
  35.         set(n);  
  36.   
  37.         char c;  
  38.         int x, y;  
  39.         while(m--)  
  40.         {  
  41.             scanf("%c%d%d%*c", &c, &x, &y); //注意输入  
  42.             //printf("%c\n", c);  
  43.             if(c == 'A')  
  44.             {  
  45.                 if(find(x) == find(y)) //如果根节点相同,则表示能判断关系  
  46.                 {  
  47.                     if(r[x] != r[y]) printf("In different gangs.\n");  
  48.                     else printf("In the same gang.\n");  
  49.                 }  
  50.                 else printf("Not sure yet.\n");  
  51.             }  
  52.             else if(c == 'D')  
  53.             {  
  54.                 Union(x, y);  
  55.             }  
  56.         }  
  57.     }  
  58.     return 0;  
  59. }  

http://www.hankcs.com/program/cpp/poj-1703-find-them-catch-them.html
无间道:有N名来自两个帮派的坏蛋,已知一些坏蛋两两不属于同一帮派,求判断给定两个坏蛋是否属于同一帮派。
2.4 加工并储存数据的数据结构
并查集
这题真的很简单,是食物链的弱化版,使用相似的思路来做即可——
定义并查集为:
并查集里的元素i-x表示i属于帮派x
同一个并查集的元素同时成立
可见所有元素个数为2 * N,如果i表示属于帮派A,那么i + N表示属于帮派B,每次输入两个家伙不在同一帮派的时候,就合并他们分属两个帮派的元素。我认为这是最简单最好懂的算法,那些利用复杂节点带权重接着依靠大量if-else维护并查集的做法都不够美。

有个小插曲,这题如果用cin的话会TLE,浪费我不少时间试图优化算法。我还是第一次遇到会让cin TLE的数据量。换用scanf就轻松AC

稍微扯远一点,最近看完了《数学之美》这本书,里面提到了最大熵模型,也就是“包含所有可能性”的模型。这道题目其实归根结底就是保留了所有可能性,我们只知道x和y不属于同一集合,但我们不能确定究竟x属于集合A还是集合B,于是我们保留所有可能性,对x-A和x-B都做了一次记录。
#define MAX_N 100000 * 2 + 16
int parent[MAX_N];
int height[MAX_N];
 
void init(const int& n)
{
    for (int i = 0; i < n; ++i)
    {
        parent[i] = i;
        height[i] = 0;
    }
}
 
int find(const int& x)
{
    if (parent[x] == x)
    {
        return x;
    }
    else
    {
        return parent[x] = find(parent[x]);
    }
}
 
void unite(int x, int y)
{
    x = find(x);
    y = find(y);
    if (x == y)
    {
        return;
    }
 
    if (height[x] < height[y])
    {
        parent[x] = y;
    }
    else
    {
        parent[y] = x;
        if (height[x] == height[y])
        {
            ++height[x];
        }
    }
}
 
bool same(const int& x, const int& y)
{
    return find(x) == find(y);
}
 
 
int main(int argc, char *argv[])
{
#ifndef ONLINE_JUDGE
    freopen("in.txt""r", stdin);
    freopen("out.txt""w", stdout);
#endif
    int T;
    cin >> T;
    while (T--)
    {
        int N, M;
        cin >> N >> M;
        init(N * 2);
        char message;
        int x, y;
        getchar();
        while (M--)
        {
            // cin 会导致TLE,哭笑不得
            // cin >> message >> x >> y;
            scanf("%c%d%d%*c", &message, &x, &y);
           if (message == 'A')
           {
               if (same(x, y))
               {
                   cout << "In the same gang." << endl;
               }
               else if (same(x, y + N))
               {
                   cout << "In different gangs." << endl;
               }
               else
               {
                   cout << "Not sure yet." << endl;
               }
           }
           else
           {
               unite(x, y + N);
               unite(x + N, y);
           }
        }
    }
#ifndef ONLINE_JUDGE
    fclose(stdin);
    fclose(stdout);
    system("out.txt");
#endif
    return 0;
}

http://www.cnblogs.com/plumrain/p/POJ_1703.html
解法:并查集基础题。用一个struct node表示每一个罪犯,node.f表示该罪犯的父亲节点,node.r表示该罪犯与父亲节点对应的罪犯的关系(0表示来自同一个帮派,1表示不同)。然后写find函数注意更新node.r就行
struct node{
14     int f, r;
15 };
17 char s[10];
18 int n, m;
19 node a[maxn];
21 void init()
22 {
23     for (int i = 0; i < n; ++ i){
24         a[i].f = i;
25         a[i].r = 0;
26     }
27 }
29 int find(int x)
30 {
31     if (x == a[x].f){
32         a[x].r = 0;
33         return x;
34     }
36     int y = a[x].f;
37     a[x].f = find(a[x].f);
38     a[x].r = (a[y].r + a[x].r) % 2;
39     return a[x].f;
40 }
42 void merge(int x, int y)
43 {
44     int t1 = find(x), t2 = find(y);
45     a[t1].f = t2;
46     a[t1].r = (a[y].r + a[x].r + 1) % 2;
47 }
49 int main()
50 {
51     int T;
52     scanf ("%d", &T);
53     while (T --){
54         scanf ("%d%d", &n, &m);
55         init();
57         int x, y;
58         while (m --){
59             scanf ("%s%d%d", s, &x, &y);
60             int t1 = find(x), t2 = find(y);
61             if (s[0] == 'D')
62                 merge(x, y);
63             else{
64                 if (t1 != t2)
65                     printf ("Not sure yet.\n");
66                 else{
67                     if (a[x].r == a[y].r)
68                        printf ("In the same gang.\n"); 
69                     else
70                         printf ("In different gangs.\n");
71                 }
72             }
73         }
74     }
75     return 0;
76 }
Read full article from 1703 -- Find them, Catch them

Labels

LeetCode (1432) GeeksforGeeks (1122) LeetCode - Review (1067) Review (882) Algorithm (668) to-do (609) Classic Algorithm (270) Google Interview (237) Classic Interview (222) Dynamic Programming (220) DP (186) Bit Algorithms (145) POJ (141) Math (137) Tree (132) LeetCode - Phone (129) EPI (122) Cracking Coding Interview (119) DFS (115) Difficult Algorithm (115) Lintcode (115) Different Solutions (110) Smart Algorithm (104) Binary Search (96) BFS (91) HackerRank (90) Binary Tree (86) Hard (79) Two Pointers (78) Stack (76) Company-Facebook (75) BST (72) Graph Algorithm (72) Time Complexity (69) Greedy Algorithm (68) Interval (63) Company - Google (62) Geometry Algorithm (61) Interview Corner (61) LeetCode - Extended (61) Union-Find (60) Trie (58) Advanced Data Structure (56) List (56) Priority Queue (53) Codility (52) ComProGuide (50) LeetCode Hard (50) Matrix (50) Bisection (48) Segment Tree (48) Sliding Window (48) USACO (46) Space Optimization (45) Company-Airbnb (41) Greedy (41) Mathematical Algorithm (41) Tree - Post-Order (41) ACM-ICPC (40) Algorithm Interview (40) Data Structure Design (40) Graph (40) Backtracking (39) Data Structure (39) Jobdu (39) Random (39) Codeforces (38) Knapsack (38) LeetCode - DP (38) Recursive Algorithm (38) String Algorithm (38) TopCoder (38) Sort (37) Introduction to Algorithms (36) Pre-Sort (36) Beauty of Programming (35) Must Known (34) Binary Search Tree (33) Follow Up (33) prismoskills (33) Palindrome (32) Permutation (31) Array (30) Google Code Jam (30) HDU (30) Array O(N) (29) Logic Thinking (29) Monotonic Stack (29) Puzzles (29) Code - Detail (27) Company-Zenefits (27) Microsoft 100 - July (27) Queue (27) Binary Indexed Trees (26) TreeMap (26) to-do-must (26) 1point3acres (25) GeeksQuiz (25) Merge Sort (25) Reverse Thinking (25) hihocoder (25) Company - LinkedIn (24) Hash (24) High Frequency (24) Summary (24) Divide and Conquer (23) Proof (23) Game Theory (22) Topological Sort (22) Lintcode - Review (21) Tree - Modification (21) Algorithm Game (20) CareerCup (20) Company - Twitter (20) DFS + Review (20) DP - Relation (20) Brain Teaser (19) DP - Tree (19) Left and Right Array (19) O(N) (19) Sweep Line (19) UVA (19) DP - Bit Masking (18) LeetCode - Thinking (18) KMP (17) LeetCode - TODO (17) Probabilities (17) Simulation (17) String Search (17) Codercareer (16) Company-Uber (16) Iterator (16) Number (16) O(1) Space (16) Shortest Path (16) itint5 (16) DFS+Cache (15) Dijkstra (15) Euclidean GCD (15) Heap (15) LeetCode - Hard (15) Majority (15) Number Theory (15) Rolling Hash (15) Tree Traversal (15) Brute Force (14) Bucket Sort (14) DP - Knapsack (14) DP - Probability (14) Difficult (14) Fast Power Algorithm (14) Pattern (14) Prefix Sum (14) TreeSet (14) Algorithm Videos (13) Amazon Interview (13) Basic Algorithm (13) Codechef (13) Combination (13) Computational Geometry (13) DP - Digit (13) LCA (13) LeetCode - DFS (13) Linked List (13) Long Increasing Sequence(LIS) (13) Math-Divisible (13) Reservoir Sampling (13) mitbbs (13) Algorithm - How To (12) Company - Microsoft (12) DP - Interval (12) DP - Multiple Relation (12) DP - Relation Optimization (12) LeetCode - Classic (12) Level Order Traversal (12) Prime (12) Pruning (12) Reconstruct Tree (12) Thinking (12) X Sum (12) AOJ (11) Bit Mask (11) Company-Snapchat (11) DP - Space Optimization (11) Dequeue (11) Graph DFS (11) MinMax (11) Miscs (11) Princeton (11) Quick Sort (11) Stack - Tree (11) 尺取法 (11) 挑战程序设计竞赛 (11) Coin Change (10) DFS+Backtracking (10) Facebook Hacker Cup (10) Fast Slow Pointers (10) HackerRank Easy (10) Interval Tree (10) Limited Range (10) Matrix - Traverse (10) Monotone Queue (10) SPOJ (10) Starting Point (10) States (10) Stock (10) Theory (10) Tutorialhorizon (10) Kadane - Extended (9) Mathblog (9) Max-Min Flow (9) Maze (9) Median (9) O(32N) (9) Quick Select (9) Stack Overflow (9) System Design (9) Tree - Conversion (9) Use XOR (9) Book Notes (8) Company-Amazon (8) DFS+BFS (8) DP - States (8) Expression (8) Longest Common Subsequence(LCS) (8) One Pass (8) Quadtrees (8) Traversal Once (8) Trie - Suffix (8) 穷竭搜索 (8) Algorithm Problem List (7) All Sub (7) Catalan Number (7) Cycle (7) DP - Cases (7) Facebook Interview (7) Fibonacci Numbers (7) Flood fill (7) Game Nim (7) Graph BFS (7) HackerRank Difficult (7) Hackerearth (7) Inversion (7) Kadane’s Algorithm (7) Manacher (7) Morris Traversal (7) Multiple Data Structures (7) Normalized Key (7) O(XN) (7) Radix Sort (7) Recursion (7) Sampling (7) Suffix Array (7) Tech-Queries (7) Tree - Serialization (7) Tree DP (7) Trie - Bit (7) 蓝桥杯 (7) Algorithm - Brain Teaser (6) BFS - Priority Queue (6) BFS - Unusual (6) Classic Data Structure Impl (6) DP - 2D (6) DP - Monotone Queue (6) DP - Unusual (6) DP-Space Optimization (6) Dutch Flag (6) How To (6) Interviewstreet (6) Knapsack - MultiplePack (6) Local MinMax (6) MST (6) Minimum Spanning Tree (6) Number - Reach (6) Parentheses (6) Pre-Sum (6) Probability (6) Programming Pearls (6) Rabin-Karp (6) Reverse (6) Scan from right (6) Schedule (6) Stream (6) Subset Sum (6) TSP (6) Xpost (6) n00tc0d3r (6) reddit (6) AI (5) Abbreviation (5) Anagram (5) Art Of Programming-July (5) Assumption (5) Bellman Ford (5) Big Data (5) Code - Solid (5) Code Kata (5) Codility-lessons (5) Coding (5) Company - WMware (5) Convex Hull (5) Crazyforcode (5) DFS - Multiple (5) DFS+DP (5) DP - Multi-Dimension (5) DP-Multiple Relation (5) Eulerian Cycle (5) Graph - Unusual (5) Graph Cycle (5) Hash Strategy (5) Immutability (5) Java (5) LogN (5) Manhattan Distance (5) Matrix Chain Multiplication (5) N Queens (5) Pre-Sort: Index (5) Quick Partition (5) Quora (5) Randomized Algorithms (5) Resources (5) Robot (5) SPFA(Shortest Path Faster Algorithm) (5) Shuffle (5) Sieve of Eratosthenes (5) Strongly Connected Components (5) Subarray Sum (5) Sudoku (5) Suffix Tree (5) Swap (5) Threaded (5) Tree - Creation (5) Warshall Floyd (5) Word Search (5) jiuzhang (5)

Popular Posts