首先明確概念:
二分圖:設G=(V,E)是一個無向圖,如果頂點V可分割為兩個互不相交的子集(A,B),並且圖中的每條邊(i,j)所關聯的兩個頂點i和j分別屬於這兩個不同的頂點集(i in A,j in B),則稱圖G為一個二分圖。
奇數環:一個圖中邊數為奇數的環。
染色法原理:
首先任意取出一個頂點進行染色,和該節點相鄰的點有三種情況:
1.如果未染色,那么繼續染色此節點(染為另一種顏色)
2.如果已染色但和當前節點顏色不同,則跳過該點
3.如果已染色並且和當前節點顏色相同,返回失敗(該圖不是二分圖)
明確二分圖、奇數環、染色法之間的關系:
如果一個圖中存在奇數環,那么這個圖一定不是二分圖;這一點顯然成立。
如果一個圖中不存在奇數環,那么這個圖一定是二分圖:
證明:用染色法。從某個點開始逐層交叉染色,在染色過程中:
若發現有某條邊的兩個端點着色相同,則必定存在奇數環①,與題意相矛盾。
若沒有發現,則根據染色法原理,每一條邊的兩端着色必然不同,那么根據二分圖的定義,就可知這個圖是一個二分圖。
①的證明:
不妨設這條邊的兩個端點着色都為1,且這兩點必然是由同一個源點擴展而來。那么根據染色法原理,因為這兩個點的着色相同,那么從源點到這兩個點所經過的邊數(假設分別為x和y)的奇偶性必然相同,那么這個環的總邊數為x+y+1,由數學知識得這個數必然是奇數。
證畢!
模板題鏈接:染色法判定二分圖
代碼如下:
#include <iostream> #include <algorithm> #include <cstring> #include <cstdio> using namespace std; const int N = 100010, M = 200010; struct Edge{ int to,next; }edge[M];int cnt; int n,m; int h[N],color[N]; void add_edge(int u,int v) { edge[++cnt].to=v; edge[cnt].next=h[u]; h[u]=cnt; } bool dfs(int u,int c) { color[u]=c; for(int i=h[u]; ~ i;i=edge[i].next) { int to=edge[i].to; if(color[to]==c) { return false; } else if(!color[to]&&!dfs(to,3-c))return false; } return true; } int main() { scanf("%d%d",&n,&m); memset(h,-1,sizeof h); for(int i=1;i<=m;i++) { int a,b;scanf("%d%d",&a,&b); add_edge(a,b);add_edge(b,a); } bool flag=true; for(int i=1;i<=n;i++) { if(!color[i]) { if(!dfs(i,1)) { flag=false; break; } } } if(flag)printf("Yes\n"); else printf("No\n"); }