hdu2813 One fihgt one (KM最小权值和)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2813


题解:KM模版题


#include <stdio.h>          
#include <string.h>         
#include <math.h>   
#define INF 0x3f3f3f3f      
#define MAXN 201    

int w[MAXN][MAXN],match[MAXN];        
int lx[MAXN],ly[MAXN],slack[MAXN];        
int visitx[MAXN],visity[MAXN];
int nx,ny;
char LvBu[MAXN][21],CaoCao[MAXN][21];

int find(int x)    
{      
	int i,temp;      
	visitx[x]=1;      
	for(i=1;i<=ny;++i)      
	{      
		if(visity[i])      
			continue;      
		temp=lx[x]+ly[i]-w[x][i];      
		if(temp==0)      
		{      
			visity[i]=1;      
			if(match[i]==-1||find(match[i]))      
			{      
				match[i]=x;      
				return 1;      
			}      
		}      
		else if(slack[i]>temp)      
		{      
			slack[i]=temp;      
		}      
	}      
	return 0;      
}      

int KM()      
{      
	int i,j,d,ans;      
	memset(ly,0,sizeof(ly));      
	memset(match,-1,sizeof(match));      
	for(i=1;i<=nx;++i)      
	{//lx初始化为与它关联边中最大的      
		lx[i]=w[i][1];      
		for(j=2;j<=ny;++j)      
			if(w[i][j]>lx[i])      
				lx[i]=w[i][j];      
	}      
	for(i=1;i<=nx;++i)      
	{      
		for(j=1;j<=ny;++j)      
			slack[j]=INF;      
		while(1)      
		{      
			memset(visitx,0,sizeof(visitx));      
			memset(visity,0,sizeof(visity));      
			if(find(i))      
				break;      
			d=INF;      
			for(j=1;j<=ny;++j)      
			{      
				if(!visity[j]&&d>slack[j])      
					d=slack[j];      
			}      
			for(j=1;j<=nx;++j)      
			{      
				if(visitx[j])      
					lx[j]-=d;      
			}      
			for(j=1;j<=ny;++j)      
			{      
				if(visity[j])      
					ly[j]+=d;      
				else      
					slack[j]-=d;      
			}      
		}      
	}      
	ans=0;        
	for(i=1;i<=ny;++i)      
	{      
		if(match[i]!=-1)   
			ans+=w[match[i]][i];     
	}  
	return ans;    
} 

int check(char *s,int flag)
{
	int i;
	if(flag)
	{
		for(i=1;i<MAXN;++i)
		{
			if(strcmp(LvBu[i],s)==0)
				return i;
			if(strcmp(LvBu[i],"")==0)
			{
				strcpy(LvBu[i],s);
				return i;
			}
		}
	}
	else
	{
		for(i=1;i<MAXN;++i)
		{
			if(strcmp(CaoCao[i],s)==0)
				return i;
			if(strcmp(CaoCao[i],"")==0)
			{
				strcpy(CaoCao[i],s);
				return i;
			}
		}
	}
} 

int main()
{
	int i,j,k,ans,val,x,y;
	char str1[21],str2[21];
	while(scanf("%d %d %d",&nx,&ny,&k)!=EOF)
	{
		memset(LvBu,'\0',sizeof(LvBu));
		memset(CaoCao,'\0',sizeof(CaoCao));
		for(i=1;i<=nx;++i)
		{
			for(j=1;j<=ny;++j)
				w[i][j]=(~INF+1);
		}
		while(k--)
		{
			scanf("%s %s %d",str1,str2,&val);
			x=check(str1,1);
			y=check(str2,0);
			w[x][y]=(~val+1);//取反
		}
		ans=KM();
		printf("%d\n",(~ans+1));
	}
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值