HiHo1121 : 二分圖一?二分圖判定(模板題)
描述
大家好,我是小Hi和小Ho的小夥伴Nettle,從這個星期開始由我來完成我們的Weekly。
新年回家,又到了一年一度大齡剩男剩女的相親時間。Nettle去姑姑家玩的時候看到了一張姑姑寫的相親情況表,上面都是姑姑介紹相親的剩男剩女們。每行有2個名字,表示這兩個人有一場相親。由於姑姑年齡比較大了記性不是太好,加上相親的人很多,所以姑姑一時也想不起來其中有些人的性別。因此她拜托我檢查一下相親表裏面有沒有錯誤的記錄,即是否把兩個同性安排了相親。
OK,讓我們愉快的暴力搜索吧!
才怪咧。
對於拿到的相親情況表,我們不妨將其轉化成一個圖。將每一個人作為一個點(編號1..N),若兩個人之間有一場相親,則在對應的點之間連接一條無向邊。(如下圖)
因為相親總是在男女之間進行的,所以每一條邊的兩邊對應的人總是不同性別。假設表示男性的節點染成白色,女性的節點染色黑色。對於得到的無向圖來說,即每一條邊的兩端一定是一白一黑。如果存在一條邊兩端同為白色或者黑色,則表示這一條邊所表示的記錄有誤。
由於我們並不知道每個人的性別,我們的問題就轉化為判定是否存在一個合理的染色方案,使得我們所建立的無向圖滿足每一條邊兩端的頂點顏色都不相同。
那麽,我們不妨將所有的點初始為未染色的狀態。隨機選擇一個點,將其染成白色。再以它為起點,將所有相鄰的點染成黑色。再以這些黑色的點為起點,將所有與其相鄰未染色的點染成白色。不斷重復直到整個圖都染色完成。(如下圖)
在染色的過程中,我們應該怎樣發現錯誤的記錄呢?相信你一定發現了吧。對於一個已經染色的點,如果存在一個與它相鄰的已染色點和它的顏色相同,那麽就一定存在一條錯誤的記錄。(如上圖的4,5節點)
到此我們就得到了整個圖的算法:
-
選取一個未染色的點u進行染色
-
遍歷u的相鄰節點v:若v未染色,則染色成與u不同的顏色,並對v重復第2步;若v已經染色,如果 u和v顏色相同,判定不可行退出遍歷。
-
若所有節點均已染色,則判定可行。
接下來就動手寫寫吧!
輸入
第1行:1個正整數T(1≤T≤10)
接下來T組數據,每組數據按照以下格式給出:
第1行:2個正整數N,M(1≤N≤10,000,1≤M≤40,000)
第2..M+1行:每行兩個整數u,v表示u和v之間有一條邊
輸出
第1..T行:第i行表示第i組數據是否有誤。如果是正確的數據輸出”Correct”,否則輸出”Wrong”
樣例輸入
2 5 5 1 2 1 3 3 4 5 2 1 5 5 5 1 2 1 3 3 4 5 2 3 5
樣例輸出
Wrong Correct
Solve:
二分圖判斷模板題
Code:
1 #include <bits/stdc++.h> 2 using namespace std; 3 int t; 4 int n , m; 5 static const int MAXN = 1e4 + 10; 6 vector <int> data[MAXN]; 7 bool flag; 8 int vis[MAXN]; 9 bool Dfs(int x , int co) 10 { 11 vis[x] = co; 12 for(auto v: data[x]) 13 { 14 if(vis[v] == co) 15 return 0; 16 if(vis[v] == -1 && !Dfs(v , !co)) 17 return 0; 18 } 19 return 1; 20 21 } 22 int main() 23 { 24 scanf("%d" , &t); 25 while(t--) 26 { 27 flag = 1; 28 scanf("%d%d" , &n , &m); 29 for(int i = 0 ; i <= n ; ++i) 30 data[i].clear() , vis[i] = -1; 31 for(int i = 1 ; i <= m ; ++i) 32 { 33 int x , y; 34 scanf("%d%d" , &x , &y); 35 data[x].push_back(y); 36 data[y].push_back(x); 37 } 38 for(int i = 0 ; i < n ; ++i) 39 { 40 if(vis[i] == -1) 41 { 42 if(!Dfs(i , 0)) 43 { 44 flag = false; 45 break; 46 } 47 } 48 } 49 50 if(flag) 51 puts("Correct"); 52 else 53 puts("Wrong"); 54 } 55 }View Code
HiHo1121 : 二分圖一?二分圖判定(模板題)