二分图最大匹配入门题

找二分图的最大匹配,就是不断得寻找增广路。

下面几题都是最大匹配的基础题,可以看出,代码基本就是一个for循环加上一个dfs深搜,其实还有一种bfs的做法,不过我还没学会。。。

POJ 1469

选课,能否找到每门课都与一个学生匹配,并且一个学生只能匹配一门课。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <vector>
using namespace std;
const int COUR = 105;
const int STU = 305;
int cor[COUR],stu[STU],visit[STU];
vector <int> G[COUR];
int p,n;
void init()
{
    memset(cor,-1,sizeof(cor));
    memset(stu,-1,sizeof(stu));

    int cot,tmp;
	scanf("%d%d",&p,&n);
	for(int i = 1;i <= p;i++)
    {
        G[i].clear();
    }
		for(int i = 0;i < p;i++)
		{
			scanf("%d",&cot);
			for(int j = 0;j < cot;j++)
			{
				scanf("%d",&tmp);
				G[i+1].push_back(tmp);
			}
		}
}
bool dfs(int u)
{
	for(int i = 0;i < G[u].size();i++)
	{
		int v = G[u][i];
		if(visit[v])
            continue;
        visit[v] = 1;
		if(stu[v] == -1 || dfs(stu[v]))
		{
			//finded the road
			cor[u] = v;
			stu[v] = u;
			return true;
		}
	}
	return false;
}
void deal()
{
	for(int i = 1;i <= p;i++)
	{
	    memset(visit,0,sizeof(visit));
		dfs(i);
	}
}
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		init();
		deal();
		int cot = 0;
		for(int i = 1;i <= p;i++)
		{
			if(cor[i] != -1)
				cot++;
		}
		if(cot == p)
			puts("YES");
		else
			puts("NO");
	}
	return 0;
}

POJ 1274

求最大牛奶产出

#include <cstdio>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <vector>
using namespace std;
const int COW = 205;
const int STALL = 205;
int n,m;
int visit[STALL];
int match[STALL];
vector <int> G[COW];
void init()
{
    int cot,tmp;
	memset(match,-1,sizeof(match));
	for(int i = 1;i <= n;i++)
	{
		G[i].clear();
	}
	for(int i = 0;i < n;i++)
	{
		scanf("%d",&cot);
		for(int j = 0;j < cot;j++)
		{
			scanf("%d",&tmp);
			G[i+1].push_back(tmp);
		}
	}
}
bool dfs(int u)
{
	for(int i = 0;i < G[u].size(); i++)
	{
		int v = G[u][i];
		if(visit[v])
			continue;
		visit[v] = 1;
		if(match[v] == -1 || dfs(match[v]))
		{
			match[v] = u;
			return true;
		}
	}
	return false;
}
int main()
{
	while(scanf("%d%d",&n,&m) != EOF)
	{
	    init();
		if(n == 0||m == 0)
		{
			puts("0");
			continue;
		}
		int ans = 0;
		for(int i = 1;i <= n;i++)
		{
			memset(visit,0,sizeof(visit));
			if(dfs(i))
				ans++;
		}
		printf("%d\n",ans);
	}
	return 0;
}

POJ 2239

还是选课。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
#include <cstdlib>
using namespace std;
const int DAY = 10;
const int CLASS = 15;
const int COUR = 305;
struct Cour
{
	int x,y;
	int p;
};
int num,p,q,n;
vector <Cour> G[COUR];
int match[DAY][CLASS];
int visit[DAY][CLASS];
bool dfs(int u)
{
	Cour t;
	for(int i = 0;i < G[u].size();i++)
	{
		t = G[u][i];
		if(visit[t.x][t.y])
			continue;
		visit[t.x][t.y] = 1;
		if(match[t.x][t.y] == -1 || dfs(match[t.x][t.y]))
		{
			match[t.x][t.y] = u;

			return true;
		}
	}
	return false;
}
void init()
{
	Cour t;
	memset(match,-1,sizeof(match));
	for(int i = 1;i <= n;i++)
		G[i].clear();
	for(int i = 1; i <= n; i++)
		{
			scanf("%d",&num);
			for(int j = 1;j <= num; j++)
			{
				scanf("%d%d",&p,&q);
				t.x = p,t.y = q;
				G[i].push_back(t);
			}
		}
}
int main()
{

	while(scanf("%d",&n)!=EOF)
	{
		init();
		int ans = 0;
		for(int i = 1;i <= n; i++)
		{
		    memset(visit,0,sizeof(visit));
			if(dfs(i))
				ans++;
		}
		printf("%d\n",ans);
	}
	return 0;
}
POJ 2536

求出最少会被伤害的gopher的个数。找出每个gopher与每个hole的距离,在距离范围内,放入图G中既可构建二分图。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <vector>
#include <cmath>
using namespace std;
const int GOP = 105;
const int HOLE = 105;
struct Position
{
	double x,y;
	int pos;
}gop[GOP],hole[HOLE];
vector <int> G[GOP];
int match[GOP],visit[GOP];
int n,m,s,v;
#define calc_dis(x1,y1,x2,y2) sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1))
void init()
{
	memset(match,-1,sizeof(match));
	for(int i = 0;i < n; i++)
	{
		G[i].clear();
		scanf("%lf%lf",&gop[i].x,&gop[i].y);
	}
	for(int i = 0;i < m; i++)
	{
		scanf("%lf%lf",&hole[i].x,&hole[i].y);
	}
	//calc distance
	for(int i = 0;i < n; i++)
	{
		for(int j = 0;j < m;j++)
		{
			if(s*v >= abs(calc_dis(hole[j].x,hole[j].y,gop[i].x,gop[i].y)))
				G[i].push_back(j);
		}
	}
}
bool dfs(int u)
{
	for(int i = 0;i < G[u].size(); i++)
	{
		int v = G[u][i];
		if(visit[v])
			continue;
        visit[v] = 1;
		if(match[v] == -1 || dfs(match[v]))
		{
			match[v] = u;
			return true;
		}
	}
	return false;
}
int main()
{
	while(scanf("%d%d%d%d",&n,&m,&s,&v) != EOF)
	{
		init();
		int ans = 0;
		for(int i = 0;i < n;i++)
		{
			memset(visit,0,sizeof(visit));
			if(dfs(i))
				ans++;
		}
		printf("%d\n",n - ans);
	}
	return 0;
}

POJ 1325

好吧,这题我看别人思路了。二分图的构造,对每个任务所给出的A机器的model和B机器的model,对两个model进行连接既可构造出二分图,求该二分图的最大匹配。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <vector>
using namespace std;
const int MODEL = 105;
int n,m,k;
int match[MODEL];
int visit[MODEL];
vector <int> G[MODEL];
void init()
{
	int t,u,v;
	memset(match,-1,sizeof(match));
	for(int i = 0;i < n;i++)
		G[i].clear();
	for(int i = 0;i < k;i++)
    {
        scanf("%d%d%d",&t,&u,&v);
        if(u == 0 || v == 0)
            continue;
        G[u].push_back(v);
	}
}
bool dfs(int u)
{
	for(int i = 0;i < G[u].size();i++)
	{
		int v = G[u][i];
		if(visit[v])
			continue;
		visit[v] = 1;
		if(match[v] == -1 || dfs(match[v]))
		{
			match[v] = u;
			return true;
		}
	}
	return false;
}
int main()
{
	while(scanf("%d",&n),n)
	{
		scanf("%d%d",&m,&k);
		init();
		int ans = 0;
		for(int i = 0;i < n;i++)
		{
			memset(visit,0,sizeof(visit));
			if(dfs(i))
				ans++;
		}
		printf("%d\n",ans);
	}
	return 0;
}

POJ 2446

把每个非hole的点看作是与该点的上下左右相连接。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <vector>
using namespace std;
const int ROW = 35;
const int COL = 35;
const int cot_dir = 4;
int m,n,k;
struct Grid
{
	int x,y;
}match[ROW][COL];
//vector <Grid> G[ROW][COL];
char Map[ROW][COL];
int visit[ROW][COL];
int dir[4][2] = {{-1,0},{1,0},{0,-1},{0,1}};
bool dfs(int t,int p)
{
	int x,y;
	visit[t][p] = 1;
	for(int i = 0;i < cot_dir;i++)
	{
		x = t + dir[i][0],y = p + dir[i][1];
		if(x >= 1&& x <= m&&y >= 1&&y <= n&& Map[x][y] == '0'&&(!visit[x][y]))
		{
			visit[x][y] = 1;
			if(match[x][y].x == -1 || dfs(match[x][y].x,match[x][y].y))
			{
				match[x][y].x = t,match[x][y].y = p;
				match[t][p].x = x,match[t][p].y = y;
				return true;
			}
		}
	}
	return false;
}
int deal()
{
    int ans = 0;
	for(int i = 1;i <= m;i++)
	{
		for(int j = 1;j <= n;j++)
		{
			if(Map[i][j] == '#' || match[i][j].x != -1)
				continue;
			memset(visit,0,sizeof(visit));
			if(dfs(i,j))
				ans++;
		}
	}
	return ans;
}
int main()
{
	while(scanf("%d%d%d",&m,&n,&k) != EOF)
	{
		int x,y,hole = 0;
		memset(Map,'0',sizeof(Map));
		memset(match,-1,sizeof(match));
		for(int i = 0;i < k; i++)
		{
			scanf("%d%d",&x,&y);
			Map[y][x] = '#';
			hole++;
		}
		int ans = deal();
		if(hole + ans*2 == m*n)
            puts("YES");
        else
            puts("NO");
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值