【洛谷P3386】【模板】二分圖匹配
阿新 • • 發佈:2017-10-03
thml stream bsp fin alt 會有 () 可能 -m
題目背景
二分圖
題目描述
給定一個二分圖,結點個數分別為n,m,邊數為e,求二分圖最大匹配數
輸入輸出格式
輸入格式:
第一行,n,m,e
第二至e+1行,每行兩個正整數u,v,表示u,v有一條連邊
輸出格式:
共一行,二分圖最大匹配
輸入輸出樣例
輸入樣例#1:1 1 1 1 1輸出樣例#1:
1
說明
n,m≤1000,1≤u≤n,1≤v≤m
因為數據有坑,可能會遇到 v>m 的情況。請把 v>m 的數據自覺過濾掉。
算法:二分圖匹配
分析
知識點:題目上都說了是二分圖最大匹配。
本題不是很難,是個模板題,想借這個模板題說一說匈牙利算法。關於增廣路,交替路網上的解釋很多,這裏默認讀者已會。
匈牙利算法是通過不斷地尋找增廣路來增加匹配數。如圖3->6->2->5->1->4就是一個增廣路,因為增廣路的初邊和終邊都是非匹配邊,所以增廣路的非匹配邊比匹配邊多1個。
只要將匹配邊變成非匹配邊,非匹配邊變成匹配邊,這樣的話匹配邊就多了一個。
關鍵的是在於代碼實現。
我們從非匹配點出發所走的邊一定是非匹配邊,如果所走到的點是非匹配點,那麽我們就已經找到了一條增廣路。
如果走到的是匹配點,我們要走的是交替路,所以下一次要走匹配邊,假如i是匹配點,match[i]是i所匹配的點,那麽i->match[i]一定是匹配邊。
這樣一直做下去,如果找到增廣路return true否則return false。
還有一點二分圖中可能會有偶環(不會有奇環的),所以要加一個vis數組來判斷這個點是否被訪問過。
代碼
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> using namespace std; const int maxn=1000+5; inline int read() { int x=0,f=1; char ch=getchar(); while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1; ch=getchar();}while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();} return x*f; } int n,m,e,ans; int match[maxn]; bool mp[maxn][maxn],vis[maxn]; bool find(int x) { for(int i=1;i<=m;i++) if(mp[x][i]&&!vis[i]) { vis[i]=1; if(!match[i]||find(match[i])) {//如果找到了,就把非匹配邊變成匹配邊 match[i]=x; return 1; } } return 0; } int main() { n=read();m=read();e=read(); for(int i=1;i<=e;i++) { int x,y; x=read();y=read(); if(y>m) continue; mp[x][y]=1;//這兒是單向邊 } for(int i=1;i<=n;i++) { memset(vis,0,sizeof(vis)); if(find(i)) ans++; } printf("%d\n",ans); return 0; }
【洛谷P3386】【模板】二分圖匹配