poj 2195 最大权匹配

本文介绍了一种使用C语言实现的匈牙利算法(Kuhn-Munkres算法),用于解决二分图的最大权匹配问题。该算法通过不断调整顶点的权值来寻找增广路径,最终得到一个完全匹配,使得所有匹配边的权重之和最大。文章中的代码实现了从输入读取二分图的顶点坐标,并计算每个顶点间的距离,然后应用匈牙利算法求解最大权匹配。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#include<stdio.h>
#include<math.h>
#define INF 0x3f3f3f3f
#define min(x,y) ((x)>(y)?(y):(x))
#define max(x,y) ((x)>(y)?(x):(y))
int n,m,A[116][2],B[116][2];
int map[100+16][100+16];
int match[100+16],ex[116],ey[116],vis_x[116],vis_y[116],slack[116];
int id1,id2;
int dfs(x)
{
	int y,gap;
	vis_x[x]=1;
	for(y=0;y<id2;y++)
	{
		if(vis_y[y])
			continue;
		gap=ex[x]+ey[y]-map[x][y];
		if(gap==0)
		{
			vis_y[y]=1;
			if(match[y]==-1||dfs(match[y]))
			{
				match[y]=x;
				return 1;
			}
		}
		else
			if(slack[y]>gap)
				slack[y]=gap;
	}
	return 0;
}
int KM(void)
{
	int i,j,d,res;
	memset(match,-1,sizeof(match));
	memset(ey,0,sizeof(ey));
	for(i=0;i<id1;i++)
	{
		ex[i]=map[i][0];
		for(j=1;j<id2;j++)
		{
			ex[i]=max(ex[i],map[i][j]);
		}
	}
	for(i=0;i<id1;i++)
	{
		memset(slack,0x3f,sizeof(slack));
		while(1)
		{
			memset(vis_x,0,sizeof(vis_x));
			memset(vis_y,0,sizeof(vis_y));
			if(dfs(i))
				break;
			d=INF;
			for(j=0;j<id2;j++)
			{
				if(!vis_y[j]&&d>slack[j])
					d=slack[j];
			}
			for(j=0;j<id1;j++)
			{
				if(vis_x[j])
					ex[j]-=d;
			}
			for(j=0;j<id2;j++)
				if(vis_y[j])
					ey[j]+=d;
				else
					slack[j]-=d;
		}
	}
	res=0;
	for(i=0;i<id1;i++)
	{
		if(match[i]>-1)
			res+=map[match[i]][i];
	}
	return res;
}
int main()
{
	int i,j;
	char st[200];

     while(~scanf("%d%d",&n,&m))
	 {
		 	memset(map,0,sizeof(map));
		 if(n==0&&m==0)
			 break;
		 id1=id2=0;
		 for(i=0;i<n;i++)
		 {
			 scanf("%s",st);
			 for(j=0;j<m;j++)
			 {
				 if(st[j]=='.')
					 continue;
				 if(st[j]=='m')
				 {
					 A[id1][0]=i;
					 A[id1++][1]=j;
				 }
				 else
				 {
					 B[id2][0]=i;
					 B[id2++][1]=j;
				 }
			 }
		 }
		 for(i=0;i<id1;i++)
		 {
			 for(j=0;j<id2;j++)
			 {
				 map[i][j]=210-(abs(A[i][0]-B[j][0])+abs(A[i][1]-B[j][1]));
			 }
		 }
		 printf("%d\n",210*id1-KM());
	 }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值