POJ 3020二分图的最大匹配

题目大意:

一个矩形中,有N个城市’*’,现在这n个城市都要覆盖无线,若放置一个基站,那么它至多可以覆盖相邻的两个城市。

问至少放置多少个基站才能使得所有的城市都覆盖无线?

解题思路:

先对图中的所有城市进行编号:

列如:

*oo

***

o*o

可以将此图转化为:

100

234

506

每个城市和其相邻的城市之间可以共用一个信号塔,那么可以将两个相邻城市用一条线来表示,线的两个端点是两个相邻的城市。然后将图用邻接矩阵表示。那么上面的图就可以转化为:

   1 2 3 4 5 6

1 0 1 0 0 0 0

2 1 0 1 0 1 0

3 0 1 0 1 0 0

4 0 0 1 0 0 1

5 0 1 0 0 0 0

6 0 0 0 1 0 0

然后就可以用匈牙利算法计算最大二分匹配数了。

需要注意的是此图是无向图,所以所有的匹配数都计算了两次,在最后计算的时候要除以二。

根据公式:无向二分图的最小路径覆盖 = 顶点数 – 最大二分匹配数/2

得出结果。

#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<vector>
#include<queue>
#include<stack>
#include<queue>
#include<algorithm>
using namespace std;
char a[500][500];
int map[500][500],line[500][500],vis[500],mark[500];
int dir4[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
int m,n,num;
bool judge(int x,int y)//判断是否越界
{
	if(x>=0&&x<m&&y>=0&&y<n)
		return true;
	return false;
}
bool find(int x)//匈牙利算法计算最大二分匹配数
{
	for(int i=1;i<num;i++)
		if(line[x][i]==1&&!vis[i])
		{
			vis[i]=1;
			if(mark[i]==0||find(mark[i]))
				{
				mark[i]=x;
				return true;
				}
		}
	return false;
}
int main()
{
	//freopen("in.txt","r",stdin);
	//freopen("out.txt","w",stdout);
	int T;
	scanf("%d",&T);
	while(T--)
	{
		memset(a,0,sizeof(a));
		memset(map,0,sizeof(map));
		memset(line,0,sizeof(line));
		memset(mark,0,sizeof(mark));
		scanf("%d%d",&m,&n);
		for(int i=0;i<m;i++)
			scanf("%s",a[i]);
		num=1;
		for(int i=0;i<m;i++)
			for(int j=0;j<n;j++)
				if(a[i][j]=='*')
				{
					map[i][j]=num;
					num++;
				}
		for(int i=0;i<m;i++)//将图转化为邻接矩阵
			for(int j=0;j<n;j++)
				if(map[i][j])
				for(int k=0;k<4;k++)
				{
					if(judge(i+dir4[k][0],j+dir4[k][1])&&map[i+dir4[k][0]][j+dir4[k][1]])
						line[map[i][j]][map[i+dir4[k][0]][j+dir4[k][1]]]=1;
				}
		int sum=0;
		for(int i=1;i<num;i++)//计算最大二分匹配数
		{
			memset(vis,0,sizeof(vis));
			if(find(i))
				sum++;
		}
		printf("%d\n",num-1-sum/2);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值