1. 程式人生 > >A Bug's Life(並查集拓展)

A Bug's Life(並查集拓展)

A Bug's Life

Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 12358    Accepted Submission(s): 4032


Problem 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! Hint
Huge input,scanf is recommended. 本題大概意思就是:例如給出a和b,表示a與b為異性,判斷所給資料是否衝突;
#include<iostream>
#include<stdlib.h>
#define Size 2005
using namespace std;
int father[Size],a[Size],s;
int find(int x){
    if(father[x]==x)
    return x;
    int t = find(father[x]);
    a[x]=(a[x]+a[father[x]])%2;
    father[x] = t;
    return father[x];
}
void merage(int x, int y){
     int fx,fy;
     fx=find(x);
     fy=find(y);   
     if(fx==fy){
        if(a[x]==a[y]){
           s= 1;  //表示衝突
        }
     }
	 else{
        father[fx]=fy;
        a[fx]=(a[x]+a[y]+1)%2;
     }
}
int main()
{
    int b,c,i,n,v,x,y;
    cin>>n;
    v=1;
    while(n--){
        cin>>x>>y;
        for(i=1;i<=x;i++){
            father[i]=i;
            a[i]=0;
        }
        s=0;
        while(y--){	
            cin>>b>>c;
            merage(b,c);
        }
        cout<<"Scenario #"<<v++<<":\n";
        if(s)cout<<"Suspicious bugs found!\n"<<endl;
        else cout<<"No suspicious bugs found!\n"<<endl;
    }
    return 0;
}

大牛詳解:

個人認為它是初級並查集問題的一個升級。同時這個題讓我看到了食物鏈的影子。。。
題目的大意是給出n只bug和m次觀察到的性行為,並以此為依據判斷兩隻bugs是不是有同性戀行為(gay)。
比如3只bug
1 2有性行為
2 3有性行為
1 3有性行為
---->>>>>首先1,2是異性。
---->>>>>然後2,3是異性。
可以推出1,3是異性。
但是1,3有性行為,所以可以判斷出有一定有同性戀。

剝離這個題目所賦予的外殼,我們抽出這個問題的本質:並查集!
其實,這裡最重要的是去維護每一個點到集合頂點的偏移量。(注意:下面生造了一個詞 所謂集合元素 比如說f[i]=i,那麼i就是集合元素,集合偏移量就是集合元素的偏移量)

初始狀態下,應該是 
i號點掛在i號集合下面
我們考慮一般情況:假設合併的過程已經進行了一部分 ,這樣每一個集合下面都有元素,且各自對於頂點的偏移量都算出來了;
現在在a集合中的元素x和b集合中的元素y進行合併。此時有兩中情況改變偏移量;
1.首先是集合的合併,如果要將a,b集合合併,又要保證x,y數字的kind不相同,比如說把b集合掛到a集合下面去。
代表集合的那個元素,他的偏移量永遠是0,所以b要改變偏移量,使得b裡面的y在進行變換後要和x相異。
如果 kind[x]=0;kind[y]=0;那麼y對應的那個代表集合的元素的偏移量必須變成1,因為只有這樣才能使得合併後,x,y有不同的kind;
如果 kind[x]=0,kind[y]=1;y對應代表集合的元素偏移量是0,所以對應集合偏移量還是0;
類推   kind[x]=1,kind[y]=0,同上,0;
           kind[x]=1,kind[y]=1,y集合偏移量應該變為1;
綜上 可以得到一個同或的關係。
用等式 kind[a]=(kind[x]+kind[y]+1)%2;恰好滿足要求.
2.然後是壓縮路徑時候的偏移量改變
個人認為,這個主要是解決集合合併時候產生的“殘餘問題”,因為在合併集合的時候只是考慮了集合的偏移量,至於它下面的元素一概不管。一個壓縮路徑既分離了父子元素的偏移量,又使得子元素直接指向集合元素。

總而言之,並查集的操作就是不斷地維護者各個集合中,每個元素身上對集合元素的偏移關係。從而確定他們是否具有同性戀。
在這個題中,假設是不存在同性戀的,所以只有找到矛盾才輸出 有同性戀。