POJ **** Butterfly(二部圖BFS遍歷染色)

題目連接:http://algorithm.openjudge.cn/betaexam/B/
(題目源自Jon Kleinberg著《Algorithm Design》第3章圖論課後習題第4題,英文原版第107頁)

總時間限制: 1000ms    單個測試點時間限制: 100ms    內存限制: 65536kB

描述

有一羣旅行愛好者,有一天,他們帶回了n只蝴蝶回來。他們相信每一隻都屬於兩個不同種類中的一種,爲了討論方便,我們稱它們爲A與B。他們想把n只標本分成兩組——一些屬於A且一些屬於B——但是直接標記任何一個標本對於他們是非常困難,因此他們決定採用下面的方法。

對每對標本i和j,他們細心地把它們放到一起研究。如果他們以自己的判斷足以確信,那麼他們把這對蝴蝶標記爲“相同”(這意味着他們相信這兩隻來自同一類)或者是“不同”(這意味着他們相信這兩隻來自不同的類)。他們也可以對某些標本判斷不出來而棄權,在這種情況下,我們稱這對標本是不明確的。

現在他們有n只標本的集合,還有對那些沒有棄權的標本對的m個判斷的集合(“相同”或者“不同”)。他們想知道這個數據與每隻蝴蝶來自A和B中的一個類的想法是否一致。更具體地說,如果對每對蝴蝶按照下述方式標記A或B是可能的,即對每個標爲“相同”的(i,j)對,就是i與j有相同標記的情況;對每個標爲“不同”的(i,j)對,就是i與j有不同標記的情況。那麼我們可以說這m個判斷是一致的。他們正在冥思苦想自己的判斷是否是一致的。請你幫他們設計合理的算法解決該問題。

輸入

輸入包含多組數據,以文件結束符爲終止。

每組數據第一行爲兩個整數,分別是n和m:
n爲蝴蝶的數量,編號從0到n-1
m爲關係的數量

接下來是m組關係數據,每組數據佔一行,爲三個整數,前兩個整數表示蝴蝶的編號,第三個整數爲關係的種類(相同或者不同):
0爲相同,1爲不同

1 < n <= 1000
1 < m <= 100000

輸出

合理就輸出YES
不合理就輸出NO

樣例輸入

3 3
0 1 0
1 2 1
0 2 1
3 3
0 1 0
1 2 1
0 2 0

樣例輸出

YES
NO

提示

注意輸出的大寫和回車

題意

n個不是A類就是B類的蝴蝶,告訴你一些蝴蝶對是相同的還是不同的,讓你判斷這樣的情況是合理(YES)還是不合理的(NO)。

解題思路

核心思想就是判斷一個圖是不是一個二部圖,但是存在一些特殊的情況需要注意。把蝴蝶對看成一條邊的話,有些點是沒有邊相連的,那麼這些點屬於哪一類對結果都沒有影響。更甚,這個圖可能是由多個連通子圖組成的,各個子圖間是相互獨立的。我的解題思路就是從某一點出發,假設這點是A類,然後把相鄰邊的點按照邊的權值來染色,如果染色矛盾就跳出輸出NO,如果BFS遍歷完所有點沒有矛盾就是YES。

BFS代碼

#include<bits/stdc++.h>
using namespace std;

int n,m,link[1005][1005],state[1005];
bool suc,vis[1005];
queue<int> vist;

bool bfs(int node)
{
    if(vis[node])   return true;
    vis[node]=1;
    if(!state[node])    state[node]=1;
    for(int i=0;i<n;i++){
        if(link[node][i]==1){
            if(!state[i])   state[i]=3-state[node];
            else if(state[i]==state[node]){
                suc=false;
                //cout<<node<<' '<<i<<"###"<<endl;
                return false;
            }
            if(!vis[i])  vist.push(i);
        }
        else if(link[node][i]==2){
            if(!state[i])   state[i]=state[node];
            else if(state[i]!=state[node]){
                suc=false;
                //cout<<node<<' '<<i<<"###"<<endl;
                return false;
            }
            if(!vis[i])  vist.push(i);
        }
    }
    return true;
}

int main()
{
    int a,b,c;
    while(~scanf("%d%d",&n,&m)){
        memset(link,0,sizeof(link));
        memset(state,0,sizeof(state));
        memset(vis,0,sizeof(vis));
        suc=true;
        while(!vist.empty())    vist.pop();
        for(int i=0;i<m;i++){
            scanf("%d%d%d",&a,&b,&c);
            link[a][b]=2-c;
            link[b][a]=2-c;
        }
        for(int i=0;i<n;i++){
            vist.push(i);
            while(!vist.empty()){
                if(!bfs(vist.front())){
                    suc=false;
                    break;
                }
                vist.pop();
            }
            if(!suc)    break;
        }
        if(suc) printf("YES\n");
        else    printf("NO\n");
    }
    return 0;
}

後記

這道題還可以利用帶偏移的並查集來求解,後期等我AC了再來更新吧。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章