URAL 1076 Trash 【最大权匹配KM快速模板O(N^3)】

题目链接:http://acm.timus.ru/problem.aspx?space=1&num=1076

我的链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=19651#problem/H


1076. Trash

Time Limit: 1.0 second
Memory Limit: 16 MB

Description

You were just hired as CEO of the local junkyard.One of your jobs is dealing with the incoming trash and sorting it for recycling.The trash comes every day in  N containers and each of these containers contains certain amount of each of the  N types of trash. Given the amount of trash in the containers find the optimal way to sort the trash. Sorting the trash means putting every type of trash in separate container. Each of the given containers has infinite capacity. The effort for moving one unit of trash from container  i to  j is 1 if  i ≠  j otherwise it is 0.You are to minimize the total effort.

Input

The first line contains the number  N (1 ≤  N ≤ 150), the rest of the input contains the descriptions of the containers.The (1 +  i)-th line contains the description of the  i-th container the  j-th amount (0 ≤ amount ≤ 100) on this line denotes the amount of the  j-th type of trash in the  i-th container.

Output

You should write the minimal effort that is required for sorting the trash.

Sample Input

input output
4
62 41 86 94
73 58 11 12
69 93 89 88
81 40 69 13
650


题意:

     你受聘于当地的垃圾处理公司任CEO,你的一项工作是处理引进的垃圾,以及分类垃圾以进行循环利用。每天,垃圾会有几个集装箱运来,每一个集装箱都包含几种垃圾。给定集装箱里垃圾的数目n,请找出最佳的途径去分类这些垃圾。分类垃圾即把每种垃圾分开装到不同的集装箱中。每个集装箱的容量都是无限的。搬动一个单位的垃圾需要耗费代价,从集装箱i到j是1(i≠j,否则代价为0),你必须把代价减到最小。

思路:

求最大权匹配的KM算法,只需把所有边的权值取相反数,求最大权匹配,结果再取相反数即可。

把垃圾筒作为点集u,垃圾总类作为点集v,建图w[i][j]表示把j类垃圾放入i 桶的代价。

分析:用前面的KM模板时间复杂度为O(N^4)容易超时。

           前面的版本修改顶标:

                枚举s和t中的每一个元素,根据定义计算最小值,每次修时间为O(N^2),总时间为O(N^4).

          快速修改顶标法:

                给t中的每个节点y定义松弛量。slack(y) = min{ l[x]+l[y]-w[x][y] }

                则a变为a = min{ slack(y)| y in t`}

                计算所有slack要O(N)时间。每次增广后最多修改N次顶标,所以每次增广后修改顶标总时间为O(N^2),程序总时间降为O(N^3).

//Accepted	216 KB	31 ms	C++	1503 B	2013-02-26 20:03:10
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=155;
const int inf=1000;
int w[maxn][maxn];
int lx[maxn],ly[maxn]; //顶标 
bool s[maxn],t[maxn];
int match[maxn];
int slack[maxn]; //点集v的松弛量 
int n;
bool hungary(int u)
{
	s[u] = true;
	for(int v=1;v<=n;v++)
	{
		if(!t[v] && lx[u]+ly[v] == w[u][v])
		{
			t[v] = true;
			if(match[v]==-1 || hungary(match[v]))
			{
				match[v]=u;
				return true;
			}
		}
		else if(slack[v] > lx[u]+ly[v]-w[u][v])//修改松弛量 
			slack[v] = lx[u]+ly[v]-w[u][v];
	}
	return false;
}
int KM()
{
	int sum=0;
	memset(match,-1,sizeof(match));
	memset(ly,0,sizeof(ly));
	for(int i=1;i<=n;i++)
	{
		lx[i]= -inf;
		for(int j=1;j<=n;j++)
			lx[i]=max(lx[i],w[i][j]);
	}	
	for(int i=1;i<=n;i++)
	{
		while(true)
		{
			memset(s,false,sizeof(s));
			memset(t,false,sizeof(t));
			for(int j=1;j<=n;j++)
				slack[j]=inf;
			if(hungary(i)) break;
			else
			{
				int a=inf;
				for(int j=1;j<=n;j++)
					if(!t[j] && slack[j]<a)
						a=slack[j];
				for(int j=1;j<=n;j++)
				{
					if(s[j]) lx[j]-=a;
					if(t[j]) ly[j]+=a;
				}
			}
		}
	}
	for(int i=1;i<=n;i++) sum+=w[match[i]][i];
	return sum;		 
}
int main()
{
	int weight;
	while(scanf("%d",&n)!=EOF)
	{
		for(int i=1;i<=n;i++)
		{
			weight=0;
			for(int j=1;j<=n;j++)
			{
				scanf("%d",&w[i][j]);
				weight+=w[i][j];
			}
			for(int j=1;j<=n;j++)
				w[i][j]=weight-w[i][j];
		}
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=n;j++)
				w[i][j] = -w[i][j];
		}	
		printf("%d\n",-KM());
	}
	return 0;
} 
  	 

   

你可能感兴趣的:(URAL 1076 Trash 【最大权匹配KM快速模板O(N^3)】)