1. 程式人生 > >Dinic演算法實現二分圖匹配

Dinic演算法實現二分圖匹配

在學習匈牙利演算法的時候便知道網路流可以以更小的時間複雜度解決同樣的問題
近期學了網路流,剛好可以再來玩兒玩兒二分圖

其實Dinic演算法在解決二分圖匹配的時候和普通的網路流題目並沒有太大區別,主要就是建圖
此時,你肯定想打我,因為網路流大部分都是考建圖(逃
具體說一下對於二分圖這種特殊的圖應該怎麼建圖(捂臉

給一張二分圖,一個集合X中含有n個元素,另一個集合Y中含有m個元素

首先,把二分圖中互相連線的點連線起來,設權值為1。恩,這一步可以看做翻譯題目;
然後,找到一個超級源點和一個超級匯點。通常前者找0,後者找n+m+1;
最後,將X中的元素都與超級源點連起來,Y中的元素都和超級匯點連起來。這些邊的權值都為1;

建圖完成,搞定收工(霧

從超級源點到超級匯點跑一波Dinic,最大匹配就素最大流啦!
至於證明,顯然可得嘛!(劃掉)網上草雞多證明的,自己百度啦~
畢竟,我不在意那些細節所以我不會。不服你打我啊~~

來一道很簡單的題目,先說匈牙利演算法是可以AC滴~~~

【rqnoj140】尋找代表元

題目描述
溫中一共有n個社團,分別用1到n編號。
溫中一共有m個人,分別用1到m編號。每個人可以參加一個或多個社團,也可以不參加任何社團。
每個社團都需要選一個代表。我們希望更多的人能夠成為代表。

輸入格式
第一行輸入兩個數n和m。以下n行每行若干個數,這些數都是不超過m的正整數。其中第i行的數表示社團i的全部成員。每行用一個0結束。

輸出格式
輸出最多的能夠成為代表的人數。

資料範圍
n,m<=200

樣例輸入
4 4
1 2 0
1 2 0
1 2 0
1 2 3 4 0

樣例輸出
3

唔,裸題不想解釋太多了。給你個眼神自己做!

#include<cstdio>
#include<vector>
#include<queue>
#include<cstring>
#define INF 1e8
using namespace std;
const int maxn=1005;
struct Edge{int from,to,cap,flow;};
int
n,m,s,t,k,x; vector<Edge>edges; vector<int>G[maxn]; bool vis[maxn]; int d[maxn]; int cur[maxn]; void AddEdge(int from,int to,int cap){ edges.push_back((Edge){from,to,cap,0}); edges.push_back((Edge){to,from,0,0}); k=edges.size(); G[from].push_back(k-2); G[to].push_back(k-1); } bool BFS(){ memset(vis,0,sizeof(vis)); queue<int>Q; Q.push(s); d[s]=0; vis[s]=true; while(!Q.empty()){ int x=Q.front();Q.pop(); for(int i=0;i<G[x].size();i++){ Edge& e=edges[G[x][i]]; if(!vis[e.to] && e.cap>e.flow){ vis[e.to]=true; d[e.to]=d[x]+1; Q.push(e.to); } } } return vis[t]; } int DFS(int x,int a){ if(x==t || a==0) return a; int flow=0,f; for(int &i=cur[x];i<G[x].size();i++){ Edge& e=edges[G[x][i]]; if(d[x]+1==d[e.to] && (f=DFS(e.to,min(a,e.cap-e.flow)))>0){ e.flow+=f; edges[G[x][i]^1].flow-=f; flow+=f; a-=f; if(a==0) break; } } return flow; } int MaxFlow(int s,int t){ int flow=0; while(BFS()){ memset(cur,0,sizeof(cur)); flow+=DFS(s,INF); } return flow; } int main(){ scanf("%d%d",&n,&m); s=0,t=n+m+1; for(int i=1;i<=n;i++){ scanf("%d",&x); while(x!=0){AddEdge(i,x+n,1);scanf("%d",&x);} } for(int i=1;i<=n;i++) AddEdge(s,i,1); for(int i=1;i<=m;i++) AddEdge(i+n,t,1); printf("%d\n",MaxFlow(s,t)); return 0; }

PS:二分圖匹配的題都可以用這種方法去操一下。
畢竟匈牙利能做的Dinic也能,Dinic能做的匈牙利不一定能。

————
菜雞我發現當年寫錯了個地方qwq