二分圖:
二分圖中,頂點可以分為兩個集合,每一條邊的端點都分別位於這兩個集合。
二分圖的判定:
可以利用Bfs或者Dfs進行黑白染色,共享一條邊的兩點異色,檢查一下是否存在矛盾即可。
相關題目:Hdu 2444 The Accomodation of Students
bfs代碼:
1 void bfs (int s) 2 { 3 int p, q, zreo, one, num; 4 queue <int> Q; 5 zreo = 1; 6 one = vis[s] = 0; 7 Q.push(s); 8 while (!Q.empty()) 9 { 10 p = Q.front(); 11 Q.pop(); 12 num = (vis[p] + 1) % 2; 13 for (int i=0; i<G[p].size(); i++) 14 { 15 q = G[p][i]; 16 if (vis[q]!=-1 && num != vis[q]) 17 flag = 1; 18 if (vis[q]==-1) 19 { 20 Q.push(q); 21 vis[q] = num; 22 if (num == 0) 23 zreo ++; 24 else 25 one ++; 26 } 27 } 28 } 29 }
dfs代碼:
1 void dfs (int u, int c, int &a, int &b) 2 { 3 b ++; 4 if (c) 5 a ++; 6 vis[u] = c; 7 for (int i=head[u]; i!=-1; i=edge[i].next) 8 { 9 int v = edge[i].to; 10 if (vis[v] == -1) 11 dfs(v, c^1, a, b); 12 } 13 }
二分圖相關問題:
二分圖最大匹配:匹配是二分圖中邊的集合,且集合中的任意邊沒有公共點,包含邊數最多的匹配。
匈牙利算法模板:
1 bool Find (int u) 2 { 3 for (int i=head[u]; i!=-1; i=edge[i].next) 4 { 5 int v = edge[i].to; 6 if (!vis[v]) 7 { 8 vis[v] = 1; 9 if (!used[v] || Find(used[v])) 10 { 11 used[v] = u; 12 return true; 13 } 14 } 15 } 16 return false; 17 }
最小頂點覆蓋:在二分圖中尋找一個盡量小的點集,使圖中每一條邊至少有一個點在該點集中。
最小頂點覆蓋 == 最大匹配。
反證法證明:假設當前存在一條兩個端點都不在最小頂點覆蓋點集中,那么這么光芒四射的邊定可以增大最大匹配邊集,與最大匹配矛盾,所以得證。
最小路徑覆蓋:在二分圖中尋找一個盡量小的邊集,使圖中每一個點都是該邊集中某條邊的端點。
最小路徑覆蓋 == 頂點數 - 最大匹配。
證明:因為一條邊最多可以包含兩個頂點,所以我們選邊的時候讓這樣的邊盡量多,也就是說最大匹配的邊集數目咯。剩下的點就只能一個邊連上一個點到集合里啦。
最大獨立集:在N個點中選出來一個最大點集,使這個點集中的任意兩點之間都沒有邊。
最大獨立集 == 頂點數 - 最大匹配。
證明:因為去掉最大匹配兩端的頂點去掉以后,剩下的點肯定是獨立集。我們再從每個匹配里面挑選出來一個點加入到獨立集中,也是不會破壞原有獨立集的獨立性的。
