1. 程式人生 > >【洛谷P3386】【模板】二分圖匹配

【洛谷P3386】【模板】二分圖匹配

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,m1000,1un,1vm

因為數據有坑,可能會遇到 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】【模板】二分圖匹配