二分圖匹配

題目:二分圖匹配
二分圖匹配,就是解決 一羣人,喜歡一類東西,而後求最多知足能知足多少人的問題。固然,東西是不一樣的,人的喜愛也是不一樣的。node

這裏講一下匈牙利算法是如何解決這個問題的。
首先,咱們畫了一個圖:

而後,咱們對第一我的匹配,也就是找第一我的要的東西,而後就獲得了下圖(粉色表明匹配成功,也就是左邊的人獲得了右邊的東西。草綠色表明遍歷過但未成功)

而後,咱們跳過一大堆已知的操做,獲得下圖:

這時,咱們發現,3號人也想要二號物品,可是已經被1號人拿走了。這改怎麼辦辦呢?咱們發現,1號還能拿3號物品。因而,人1把物2給了人3,拿了物3。

而後, 匹配4號。這時……人2佔了物1,但人2不能拿別的東西了。因而乎,人2拒絕妥協,人4被人2暴打了一頓而人4匹配不了其餘的,由於他對物品1情有獨鍾,不喜歡別的東西,so,他莫得東西了QwQ。c++

如今,全部的人都匹配完了,能拿到東西的最多有三我的,4號被拋棄了,還被暴打了一頓,最大匹配數也就是3。算法

那麼,具體思路講完了,改怎麼實現呢?
很簡單,咱們逐個枚舉人,\(dfs(i)=1\)表示匹配成功,不然失敗。用\(1\)\(chos\)數組,\(chos_i\)表示第\(i\)個物品被第\(chos_i\)我的拿走了,\(vis\)數組用來在判斷一我的可否拿別的物品時用的。也就是作個標記,若是不作這個標記,那再判斷這我的可否拿別的物品時他也許還會選擇這個物品。(因此,每次\(dfs\)都要清空\(vis\)\(dfs\)內部就是枚舉他喜歡的每個東西,若是這個東西沒人要或要這個東西的人能夠拿別的,這個東西就歸他了,而後返回1。若是遍歷完全部他想要的還得不到任何東西,就返回0。
\(vis\)數組要在每一次遍歷的時候清空哦數組

上代碼:spa

#include<bits/stdc++.h>
using namespace std;
int n,m,e,ans;//e是邊數,ans是答案
bool vis[100005];
int chos[100005];
struct node
{
	int tot;
	int dt[10000005],nxt[10000005];
	int hd[100005];
	void add(int x,int y)
	{
		tot++;
		nxt[tot]=hd[x];
		hd[x]=tot;
		dt[tot]=y;
		return ;
	}
}g;//鏈式前向星存圖
bool dfs(int x)
{
	for(int i=g.hd[x];i;i=g.nxt[i])//枚舉他喜歡的每個東西
	{
		if(vis[g.dt[i]]) continue;//被判斷過,就直接下一個循環
		vis[g.dt[i]]=1;//標記,若是不標記,後面的判斷dfs(chos[g.dt[i]])就永遠是真了。
		if(!chos[g.dt[i]]||dfs(chos[g.dt[i]]))//若是當前沒人要這個東西或要這個東西的人還能夠拿別的,那這個東西就是他的了
		{
			chos[g.dt[i]]=x;//標記這個東西歸他了
			return 1;//返回true。
		}
	}
	return 0;//到遍歷完還沒獲得東西,返回false
}
int main()
{
	scanf("%d%d%d",&n,&m,&e);
	for(int i=1;i<=e;i++)
	{
		int u,v;
		scanf("%d%d",&u,&v);
		if(u>n||v>m) continue;//題目中說有可能會出現u>n和v>m的狀況
		g.add(u,v);//連邊
	}
	for(int i=1;i<=n;i++)//枚舉每一個人
	{
		memset(vis,0,sizeof(vis));//清空vis
		ans+=dfs(i);//直接加就能夠了,由於bool中true的值是1,false的值是0
	}
	printf("%d",ans);
	return 0;
}
相關文章
相關標籤/搜索