HDU 2813 One fihgt one(KM算法解决最小权值匹配)

One fihgt one
Lv Bu and his soldiers are facing a cruel war——Cao Cao had his best generals just miles away. 
 
There’s little time , but Lv Bu is unaware of how to arrange his warriors , what he know is that he have n brave generals while Cao Cao has m , and he has k fights to choose from , he’d like to make all his n warriors participate in the battle but get the least injuries . Lv Bu is happy because there is always a good solution . So , now is your task to tell Lv Bu the least injuries his troop would get. 
No one could take part in two fights.
InputMultiple cases. For each case ,there are three integers in the first line , namely n,m (1<=n<=m<=200)and k (n<=k<=m*n). 
The next k lines are the information about k possible fights , for each line are two strings (no more than 20 characters ) and an integer. The first string indicates Lv Bu’s general and the second , of course , Cao Cao’s , and the integer is the injury Lv Bu’s general would get if this fight were chosen. OutputOne integer , the least injuries Lv Bu’s generals would get. Sample Input
2 3 5
LvBu ZhangFei 6
LvBu GuanYu 5
LvBu XuChu 4
ZhangLiao ZhangFei 8
ZhangLiao XuChu 3

Sample Output

8

题目意思说吕布和曹操两军对垒,现在派将军就叫阵。吕布一方有N个将军,曹操一方有M个将军。然后有K个关系,每个关系由3元描述,吕布一方的将军名字,曹操一方的将军名字,如果两者对战将会损失X点血量。

现在问吕布一方在尽可能出战的情况下(别人来叫阵不能不出)损失的最小血量。


那么这个就有点像二分图匹配了,而且是带边权的二分图匹配。

左边是吕布的将军,右边是曹操的将军。现在要损失的血量最小,那么就找边权最小的将军对战(挑软柿子捏)


求二分图最大边权匹配我们有KM算法,现在使求二分图最小边权匹配。

其实只需要在KM算法上改一点就可以。把每条边的边权改为负值。

这样求出来的答案就是负值,且是所有可能中负值最大一个。

在去负值,那就是最小了,此时答案就是所有可能中最小的一个。也就是最小边权匹配。


有一道类似的题目,大家可以也可以看看点我传送 (๑ •̀ㅂ•́) ✧


#include<iostream>
#include<cstdio>
#include<cstring>
#include<functional>
#include<algorithm>
#include<map>
#define maxn 240
#define inf 0x3f3f3f3f
using namespace std;
int n,m,k;
map<string,int>mapsx,mapsy;
int link[maxn][maxn];
int match[maxn];
int slack[maxn];
bool visx[maxn],visy[maxn];
int ex[maxn],ey[maxn];
bool dfs(int x)
{
	visx[x]=1;
	for(int y=1;y<=m;y++)
	{
		if(visy[y])
			continue;
		int gap=ex[x]+ey[y]-link[x][y];
		if(gap==0)
		{
			visy[y]=1;
			if(match[y]==0||dfs(match[y]))
			{
				match[y]=x;
				return 1;
			}
		}
		else
			slack[y]=min(slack[y],gap);
	}
	return 0;
}

int KM()
{
	int i,j;
	memset(ex,0,sizeof(ex));
	memset(ey,0,sizeof(ey));
	memset(match,0,sizeof(match));
	for(i=1;i<=n;i++)
	{
		ex[i]=link[i][1];
		for(j=2;j<=m;j++)
			ex[i]=max(ex[i],link[i][j]);
	}
	for(i=1;i<=n;i++)
	{
		memset(slack,0x3f,sizeof slack);//fill(slack,slack+m+1,inf);
		while(1)
		{
			memset(visx,0,sizeof(visx));
			memset(visy,0,sizeof(visy));
			if(dfs(i))
				break;
			else
			{
			int d=inf;
			for(j=1;j<=m;j++)
				if(!visy[j])
					d=min(d,slack[j]);
			for(j=1;j<=n;j++)
				if(visx[j])
					ex[j]-=d;
			for(j=1;j<=m;j++)
				if(visy[j])
					ey[j]+=d;
				else
					slack[j]-=d;
			}
		}
	}
	int sum=0;
	for(i=1;i<=m;i++)
		sum+=link[match[i]][i];
	return sum;
}

int main()
{
	int i,j,cntx,cnty,c;
	int ans;
	char a[30],b[30];
	while(scanf("%d%d%d",&n,&m,&k)!=EOF)
	{
		for(i=1;i<=n;i++)
		{
			for(j=1;j<=m;j++)
				link[i][j]=-inf;//初始化地图,应该初始化为-inf
		}//开始初始化为0错了好久
		cntx=cnty=1;
		for(i=1;i<=k;i++)
		{
			scanf("%s%s%d",&a,&b,&c);
			if(mapsx.find(a)==mapsx.end())//把人名映射
				mapsx[a]=cntx++;
			if(mapsy.find(b)==mapsy.end())
				mapsy[b]=cnty++;
			link[mapsx[a]][mapsy[b]]=-c;
		}
		ans=KM();//二分图最大权值匹配
		printf("%d\n",-ans);
	}
}


全部评论

相关推荐

10-07 20:48
门头沟学院 Java
听说改名就会有offer:可能是实习上着班想到后面还要回学校给导师做牛马,看着身边都是21-25的年纪,突然emo了了
点赞 评论 收藏
分享
一名愚蠢的人类:多少games小鬼留下了羡慕的泪水
投递荣耀等公司10个岗位
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务