二分图的最大匹配——网络流+匈牙利算法

二分图的最大匹配:首先需要判断一个图是否为二分图,若是,才继续建模;

匈牙利算法,时间复杂度n*m;

poj1274 匈牙利算法模板题目;

/*poj1274二分图最大匹配,匈牙利算法,时间复杂度n*m*/
#include<cstdio>
#include<cstring>
#include<cmath>
#include<climits>
#include<cctype>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<set>
#include<stack>
#include<string>
#include<map>
#define ll long long
#define MAX 1000
#define eps 1e-8
#define INF INT_MAX

using namespace std;

vector<int>G[MAX];

int Left[MAX],n,m;    //Left[i]记录二分图匹配中与右节点i相连的左节点,实际最终求得的匹配信息就记录在Left中 
bool T[MAX];

bool match(int u){
	for (int i = 0 ; i<G[u].size(); i++) if (!T[G[u][i]]){
		int v = G[u][i];
		T[v] = true;
		if (!Left[v] || match(Left[v])){
			Left[v] = u;
			return true;
		}
	}
	return false;
}

int KM(){
	int cnt = 0;
	memset(Left,0,sizeof(Left));
	for (int i = 1; i<=n; i++){
		memset(T,0,sizeof(T));
		if (match(i)) cnt++;    //cnt记录匹配数; 
	}
	return cnt;
}

int main(){
	while (scanf("%d%d",&n,&m) != EOF){
		int c,t;
		for (int i = 0; i<=n; i++) G[i].clear();
		for (int i = 1; i<=n; i++){
			scanf("%d",&c);
			while (c--){
				scanf("%d",&t);
				G[i].push_back(t);
			}
		}
		printf("%d\n",KM());
	}
	return 0;
}


网络流做法:建图,虚拟一个源点s,和一个汇点t,将原图中的左节点部分全部与s相连s->i,流量定为1;将原图中右节点部分全部与t相连i->t,流量也定位1;原图中已有的网络不变,流量为1。求一条从源点s到汇点t的最大流,即是匹配数,其中有流量的的边,即为匹配边;

poj1274网络流做法;

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<cctype>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<map>
#include<string>
#include<stack>
#include<set>
#define ll long long
#define MAX 1000
#define INF INT_MAX
#define eps 1e-8

using namespace std;

struct Edge{
	int from,to,cap,flow;
};

vector<int>G[MAX];
vector<Edge>edges;

void init(){
	for (int i=0; i<MAX; i++) G[i].clear();
	edges.clear();
}

void addEdge(int from, int to, int cap){
	edges.push_back((Edge){from,to,cap,0});
	edges.push_back((Edge){to,from,0,0});   //添加反向边
	int k = edges.size();
	G[from].push_back(k-2);
	G[to].push_back(k-1);
}

int d[MAX];

bool bfs(int s, int t){
	bool vis[MAX];
	queue<int>q;
	memset(vis,false,sizeof(vis));
	d[s] = 0;
	q.push(s);
	vis[s] = true;
	while (!q.empty()){
		int u = q.front();
		q.pop();
		for (int i=0; i<G[u].size(); i++){
			Edge e = edges[G[u][i]];
			if (!vis[e.to] && e.cap > e.flow){
				vis[e.to] = true;
				d[e.to] = d[u] + 1;
				q.push(e.to);
			} 
		}
	}
	return vis[t];
}

int cur[MAX];

int dfs(int s, int t, int a){
	if (s == t || a == 0) return a;
	int flow = 0, f;
	for (int&i = cur[s]; i < G[s].size(); i++){
		Edge& e = edges[G[s][i]];
		if (d[s] + 1 == d[e.to] && (f = dfs(e.to,t,min(a,e.cap - e.flow))) > 0){
			e.flow += f;
			edges[G[s][i]^1].flow -= f;
			flow += f;
			a -= f;
			if (a == 0) break;
		}
	}
	return flow;
}

int Maxflow(int s, int t){          //s为源点,t为汇点的最大流
	int flow = 0;
	while (bfs(s,t)){
		memset(cur,0,sizeof(cur));
		flow += dfs(s,t,INF);
	}
	return flow;
}

int main(){
	int n,m;
	while (scanf("%d%d",&n,&m) != EOF){
		init();
		int s = 0, t = n+m+1;
		int c,temp,u;
		for (int i = 1; i<=n; i++){
			addEdge(s,i,1);
			scanf("%d",&c);
			while (c--){
				scanf("%d",&u);
				addEdge(i,u+n,1);
			}
		}
		for (int i = 1; i<=m; i++) addEdge(i+n,t,1);
		printf("%d\n",Maxflow(s,t));
	}
	return 0;
}








  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值