POJ 2492 A Bug's Life (並查集應用的擴展)


A Bug's Life
Time Limit: 10000MS   Memory Limit: 65536K
Total Submissions: 21637   Accepted: 7056

Description

Background
Professor Hopper is researching the sexual behavior of a rare species of bugs. He assumes that they feature two different genders and that they only interact with bugs of the opposite gender. In his experiment, individual bugs and their interactions were easy to identify, because numbers were printed on their backs.
Problem
Given a list of bug interactions, decide whether the experiment supports his assumption of two genders with no homosexual bugs or if it contains some bug interactions that falsify it.

Input

The first line of the input contains the number of scenarios. Each scenario starts with one line giving the number of bugs (at least one, and up to 2000) and the number of interactions (up to 1000000) separated by a single space. In the following lines, each interaction is given in the form of two distinct bug numbers separated by a single space. Bugs are numbered consecutively starting from one.

Output

The output for every scenario is a line containing "Scenario #i:", where i is the number of the scenario starting at 1, followed by one line saying either "No suspicious bugs found!" if the experiment is consistent with his assumption about the bugs' sexual behavior, or "Suspicious bugs found!" if Professor Hopper's assumption is definitely wrong.

Sample Input

2
3 3
1 2
2 3
1 3
4 2
1 2
3 4

Sample Output

Scenario #1:
Suspicious bugs found!

Scenario #2:
No suspicious bugs found!
 1 /* 功能Function Description:     POJ-2492 並查集應用的擴展
 2    開發環境Environment:          DEV C++ 4.9.9.1
 3    技術特點Technique:
 4    版本Version:
 5    作者Author:                   可笑痴狂
 6    日期Date:                      20120808
 7    備注Notes:
 8 關於並查集,注意兩個概念:按秩合並、路徑壓縮。
 9 1、按秩合並
10 由於並查集一般是用比較高效的樹形結構來表示的,按秩合並的目的就是防止產生退化的樹(也就是類似鏈表的樹),
11 用一個數組記錄各個元素的高度(也有的記錄各個元素的孩子的數目,具體看哪種能給解題帶來方便),
12 然后在合並的時候把高度小的嫁接到高度大的上面,從而防止產生退化的樹。
13 2、路徑壓縮
14 而另一個數組記錄各個元素的祖先,這樣就防止一步步地遞歸查找父親從而損失的時間。因為並查集只要搞清楚各個元素所在的集合,
15 而區分不同的集合我們用的是代表元素(也就是樹根),所以對於每個元素我們只需保存其祖先,從而區分不同的集合。
16 而我們這道題並沒有使用純正的並查集算法,而是對其進行了擴展,
17 我們並沒有使用“1、按秩合並”(當然你可以用,那樣就需要再開一個數組)
18 我們從“1、按秩合並”得到啟示,保存“秩”的數組保存的是    元素相對於父節點的關系  ,我們豈不可以利用這種關系
19 (即相對於父節點的不同秩值來區分不同的集合),從而可以把兩個集合合並成一個集合。
20 (注:此代碼 relation=0 代表 和父節點同一性別)
21 */
22 
23 
24 #include<stdio.h>
25 int father[2005];
26 int relation[2005];
27 
28 int find_father(int i)
29 {
30     int t;
31     if(father[i]==i)
32         return i;
33 
34     //計算相對於新的父節點(即根)的秩,relation[t]是老的父節點相對於新的父節點(即根)的秩,relation[i]是i元素相對於老的父節點的秩,
35     //類似於物理里的相對運動,得到的r[i]就是相對於新的父節點(即根)的秩。而且這個遞歸調用不會超過兩層
36     t=father[i];    
37     father[i]=find_father(father[i]);
38     relation[i]=(relation[i]+relation[t]+1)%2;   //注意遞歸中把這棵樹relation中的的值都更新一遍,這句的順序 不能 和上一句 調換位置
39     // relation[a]的改變是伴隨着father[a]的改變而更新的(有father改變就有relation改變),要是father改變了,而relation未改變,此時的relation就記錄了一個錯誤的值,
40     //father未改變(即使實際的father已不是現在的值,但只要father未改變,relation的值就是“正確”的,認識到這點很重要。)
41     return father[i];
42 }
43 
44 void merge(int a,int b)
45 {
46     int x,y;
47     x=find_father(a);
48     y=find_father(b);
49     father[x]=y;
50     relation[x]=(relation[b]-relation[a])%2;//relation[a]+relation[x]與relation[b]相對於新的父節點必須相差1個等級,因為他們不是gay
51 }                                            //x下邊的節點不用改,因為查找的時候會自動更新
52 
53 int main()
54 {
55     int T,m,n,i,j,a,b,flag;
56     scanf("%d",&T);
57     for(i=1;i<=T;++i)
58     {
59         flag=0;
60         scanf("%d%d",&n,&m);
61         for(j=1;j<=n;++j)       //初始化
62         {
63             father[j]=j;
64             relation[j]=1;
65         }
66         for(j=1;j<=m;++j)
67         {
68             scanf("%d%d",&a,&b);
69             if(find_father(a)==find_father(b))
70             {
71             //    if(relation[a]!=(relation[b]+1)%2)
72                 if(relation[a]==relation[b])            //說明是同性
73                     flag=1;
74             }
75             else
76                 merge(a,b);
77         }
78         if(flag)
79             printf("Scenario #%d:\nSuspicious bugs found!\n\n",i);
80         else
81             printf("Scenario #%d:\nNo suspicious bugs found!\n\n",i);
82     }
83     return 0;
84 }

 復習並查集,又重新做了一遍:

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cstring>
 4 
 5 using namespace std;
 6 
 7 const int MAX = 2005;
 8 
 9 bool flag;
10 int fa, fb, n;
11 int father[MAX], rela[MAX];
12 
13 int find(int x)
14 {
15     if(father[x] == -1)
16         return x;
17     else
18     {
19         int tmp = father[x];
20         father[x] = find(father[x]);
21         
22         rela[x] = (rela[x]+rela[tmp])%2; 
23         return father[x];
24     }
25 }
26 
27 int main()
28 {
29     int T, m, a, b;
30     scanf("%d", &T);
31     for(int k = 1; k <= T; ++k)
32     {
33         flag = true;
34         scanf("%d%d", &n, &m);
35         {
36             memset(father, -1, (n+1)*sizeof(int));
37             memset(rela, 0, (n+1)*sizeof(int));
38             while(m--)
39             {
40                 scanf("%d%d", &a, &b);
41                 if(!flag)
42                     continue;
43                 fa = find(a);
44                 fb = find(b);
45                 
46                 if(fa != fb)
47                 {
48                     father[fa] = fb;
49                     rela[fa] = (rela[a] + rela[b] + 1)%2;
50                 }
51                 else
52                 {
53                     if(rela[a] == rela[b])
54                         flag = false;
55                 }
56                 
57             }
58             
59             printf("Scenario #%d:\n", k);
60             if(flag)   
61                 printf("No suspicious bugs found!\n\n");
62             else
63                 printf("Suspicious bugs found!\n\n");                  
64         }
65     }
66     return 0; 
67 }    

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM