Trash

Time limit: 1.0 second
Memory limit: 64 MB
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 output
4
62 41 86 94
73 58 11 12
69 93 89 88
81 40 69 13
650
Problem Author: Jivko Ganev
【题意】有n个垃圾桶,每个垃圾桶内有n种垃圾,现在是要你把垃圾分类,到每一个垃圾桶最后都只能装一种垃圾,从一个垃圾桶里把垃圾移到另一个垃圾桶会有所消耗,且都是单位消耗。。

【分析】 那么,要总消耗最少,就要原来每个垃圾桶各自保留的垃圾总和要最多,这么看来,问题就可以转化为带权二分图的最佳匹配问题。

求出这个最佳匹配  k   最后 ans = s(所有垃圾总和)-k。下面介绍一下KM最大权匹配。

解析来自 http://blog.csdn.net/x_y_q_/article/details/51927054

还是没看懂一般图都是最大匹配问题。。怪我太笨了哎~ 先来个看明白了的KM算法——寻找带权二分图的最佳匹配方法

一般对KM算法的描述,基本上可以概括成以下几个步骤:

(1) 初始化可行标杆
(2) 用匈牙利算法寻找完备匹配
(3) 若未找到完备匹配则修改可行标杆
(4) 重复(2)(3)直到找到相等子图的完备匹配

关于该算法的流程及实施,网上有很多介绍,基本上都是围绕可行标杆如何修改而进行的讨论,至于原理并没有给出深入的探讨。

KM算法是用于寻找带权二分图最佳匹配的算法。

二分图是这样一种图:所有顶点可以分成两个集:X和Y,其中X和Y中的任意两个在同一个集中的点都不相连,而来自X集的顶点与来自Y集的顶点有连线。当这些连线被赋于一定的权重时,这样的二分图便是带权二分图。

二分图匹配是指求出一组边,其中的顶点分别在两个集合中,且任意两条边都没有相同的顶点,这组边叫做二分图的匹配,而所能得到的最大的边的个数,叫做二分图的最大匹配。

我们也可以换个角度看二分图的最大匹配,即二分图的每条边的默认权重为1,我们求到的二分图的最大匹配的权重最大。对于带权二分图,其边有大于0的权重,找到一组匹配,使其权重最大,即为带权二分图的最佳匹配。

匈牙利算法一般用于寻找二分图的最大匹配。算法根据一定的规则选择二分图的边加入匹配子图中,其基本模式为:

初始化匹配子图为空
While 找得到增广路径
Do 把增广路径添加到匹配子图中

增广路径有如下特性:
1. 有奇数条边
2. 起点在二分图的X边,终点在二分图的Y边
3. 路径上的点一定是一个在X边,一个在Y边,交错出现。
4. 整条路径上没有重复的点
5. 起点和终点都是目前还没有配对的点,其他的点都已经出现在匹配子图中
6. 路径上的所有第奇数条边都是目前还没有进入目前的匹配子图的边,而所有第偶数条边都已经进入目前的匹配子图。奇数边比偶数边多一条边
7. 于是当我们把所有第奇数条边都加到匹配子图并把条偶数条边都删除,匹配数增加了1.

例如下图,蓝色的是当前的匹配子图,目前只有边x0y0,然后通过x1找到了增广路径:x1y0->y0x0->x0y2

其中第奇数第边x1y0和x0y2不在当前的匹配子图中,而第偶数条边x0y0在匹配子图中,通过添加x1y0和x0y2到匹配子图并删除x0y0,使得匹配数由1增加到了2。每找到一条增广路径,通过添加删除边,我们总是能使匹配数加1.

增广路径有两种寻径方法,一个是深搜,一个是宽搜。例如从x2出发寻找增广路径,如果是深搜,x2找到y0匹配,但发现y0已经被x1匹配了,于是就深入到x1,去为x1找新的匹配节点,结果发现x1没有其他的匹配节点,于是匹配失败,x2接着找y1,发现y1可以匹配,于是就找到了新的增广路径。如果是宽搜,x1找到y0节点的时候,由于不能马上得到一个合法的匹配,于是将它做为候选项放入队列中,并接着找y1,由于y1已经匹配,于是匹配成功返回了。相对来说,深搜要容易理解些,其栈可以由递归过程来维护,而宽搜则需要自己维护一个队列,并对一路过来的路线自己做标记,实现起来比较麻烦。

对于带权重的二分图来说,我们可以把它看成一个所有X集合的顶点到所有Y集合的顶点均有边的二分图(把原来没有的边添加入二分图,权重为0即可),也就是说它必定存在完备匹配(即其匹配数为min(|X|,|Y|))。为了使权重达到最大,我们实际上是通过贪心算法来选边,形成一个新的二分图(我们下面叫它二分子图好了),并在该二分图的基础上寻找最大匹配,当该最大匹配为完备匹配时,我们可以确定该匹配为最佳匹配。(在这里我们如此定义最大匹配:匹配边数最多的匹配和最佳匹配:匹配边的权重和最大的匹配。)

贪心算法总是将最优的边优先加入二分子图,该最优的边将对当前的匹配子图带来最大的贡献,贡献的衡量是通过标杆来实现的。下面我们将通过一个实例来解释这个过程。

有带权二分图:


算法把权重转换成标杆,X集跟Y集的每个顶点各有一个标杆值,初始情况下权重全部放在X集上。由于每个顶点都将至少会有一个匹配点,贪心算法必然优先选择该顶点上权重最大的边(最理想的情况下,这些边正好没有交点,于是我们自然得到了最佳匹配)。最初的二分子图为:(可以看到初始化时X标杆为该顶点上的最大权重,而Y标杆为0)


从X0找增广路径,找到X0Y4;从X1找不到增广路径,也就是说,必须往二分子图里边添加新的边,使得X1能找到它的匹配,同时使权重总和添加最大。由于X1通往Y4而Y4已经被X0匹配,所以有两种可能,一个是为X0找一个新的匹配点并把Y4让给X1,或者是为X1找一个新的匹配点,现在我们将要看到标杆的作用了。根据传统的算法描述,能够进入二分子图的边的条件为L(x)+L(y)>=weight(xy)。当找不到增广路径时,对于搜索过的路径上的XY点,设该路径上的X顶点集为S,Y顶点集为T,对所有在S中的点xi及不在T中的点yj,计算d=min{(L(xi)+L(yj)-weight(xiyj))},从S集中的X标杆中减去d,并将其加入到T集中的Y的标杆中,由于S集中的X标杆减少了,而不在T中的Y标杆不变,相当于这两个集合中的L(x)+L(y)变小了,也就是,有新的边可以加入二分子图了。从贪心选边的角度看,我们可以为X0选择新的边而抛弃原先的二分子图中的匹配边,也可以为X1选择新的边而抛弃原先的二分子图中的匹配边,因为我们不能同时选择X0Y4和X1Y4,因为这是一个不合法匹配,这个时候,d=min{(L(xi)+L(yj)-weight(xiyj))}的意义就在于,我们选择一条新的边,这条边将被加入匹配子图中使得匹配合法,选择这条边形成的匹配子图,将比原先的匹配子图加上这条非法边组成的非法匹配子图的权重和(如果它是合法的,它将是最大的)小最少,即权重最大了。好绕口的。用数学的方式表达,设原先的不合法匹配(它的权重最大,因为我们总是从权重最大的边找起的)的权重为W,新的合法匹配为W’,d为min{W-W’i}。在这个例子中,S={X0,
X1},Y={Y4},求出最小值d=L(X1)+L(Y0)-weight(X1Y0)=2,得到新的二分子图:


重新为X1寻找增广路径,找到X1Y0,可以看到新的匹配子图的权重为9+6=15,比原先的不合法的匹配的权重9+8=17正好少d=2。
接下来从X2出发找不到增广路径,其走过的路径如蓝色的路线所示。形成的非法匹配子图:X0Y4,X1Y0及X2Y0的权重和为22。在这条路径上,只要为S={X0,X1,X2}中的任意一个顶点找到新的匹配,就可以解决这个问题,于是又开始求d。
d=L(X0)+L(Y2)-weight(X0Y2)=L(X2)+L(Y1)-weight(X2Y1)=1.
新的二分子图为:

重新为X2寻找增广路径,如果我们使用的是深搜,会得到路径:X2Y0->Y0X1->X1Y4->Y4X0->X0Y2,即奇数条边而删除偶数条边,新的匹配子图中由这几个顶点得到的新的权重为21;如果使用的是宽搜,会得到路径X2Y1,另上原先的两条匹配边,权重为21。假设我们使用的是宽搜,得到的新的匹配子图为:


接下来依次类推,直到为X4找到一个匹配点。

KM算法的最大特点在于利用标杆和权重来生成一个二分子图,在该二分子图上面找最大匹配,而且,当些仅当找到完备匹配,才能得到最佳匹配。标杆和权重的作用在于限制新边的加入,使得加入的新边总是能为子图添加匹配数,同时又令权重和得到最大的提高。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <string>
#include <stack>
#include <queue>
#include <vector>
#define inf 0x3f3f3f3f
#define met(a,b) memset(a,b,sizeof a)
typedef long long ll;
using namespace std;
const int N = 1e2+;
const int M = ;
int w[N][N];
int lx[N], ly[N];
int visx[N], visy[N];
int link[N];
int n;
int can(int t) {
visx[t] = ;
for(int i = ; i <= n; i++) {
if(!visy[i] && lx[t] + ly[i] == w[t][i]) {
visy[i] = ;
if(link[i] == - || can(link[i])) {
link[i] = t;
return ;
}
}
}
return ;
} int km() {
int d,sum=;
met(ly,);
for(int i=;i<=n;i++){
lx[i]=-inf;
for(int j=;j<=n;j++){
lx[i]=max(lx[i],w[i][j]);
}
}
met(link,-);
for(int i=;i<=n;i++){
while(){
met(visx,);met(visy,);
if(can(i))break;
int d=inf;
for(int j=;j<=n;j++){
if(visx[j]){
for(int k=;k<=n;k++){
if(!visy[k]){
d=min(d,lx[j]+ly[k]-w[j][k]);
}
}
}
}
if(d==inf)return -;
for(int j=;j<=n;j++)if(visx[j])lx[j]-=d;
for(int j=;j<=n;j++)if(visy[j])ly[j]+=d;
}
}
for(int i=;i<=n;i++)if(link[i]!=-)sum+=w[link[i]][i];
return sum;
} int main() {
int ans = ;
scanf("%d", &n);
for(int i = ; i <= n; i++)
for(int j = ; j <= n; j++) {
scanf("%d", &w[i][j]);
ans += w[i][j];
}
ans -= km();
printf("%d\n", ans);
return ;
}

URAL 1076 Trash Trash(最大权匹配)的更多相关文章

  1. kuangbin带你飞 匹配问题 二分匹配 + 二分图多重匹配 + 二分图最大权匹配 + 一般图匹配带花树

    二分匹配:二分图的一些性质 二分图又称作二部图,是图论中的一种特殊模型. 设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j ...

  2. POJ2195 Going Home[费用流|二分图最大权匹配]

    Going Home Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 22088   Accepted: 11155 Desc ...

  3. hdu 2255 二分图最大权匹配 *

    题意:说在遥远的地方有一个非常富裕的村落,有一天,村长决定进行制度改革:重新分配房子.这可是一件大事,关系到人民的住房问题啊.村里共有n间房间,刚好有n家老百姓,考虑到每家都要有房住(如果有老百姓没房 ...

  4. HDU(2255),KM算法,最大权匹配

    题目链接 奔小康赚大钱 Time Limit: 1000/1000MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Su ...

  5. 二分图 最大权匹配 km算法

    这个算法的本质还是不断的找增广路: KM算法的正确性基于以下定理:若由二分图中所有满足A[i]+B[j]=w[i,j]的边(i,j)构成的子图(称做相等子图)有完备匹配,那么这个完备匹配就是二分图的最 ...

  6. hdu 2255 奔小康赚大钱 最大权匹配KM

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2255 传说在遥远的地方有一个非常富裕的村落,有一天,村长决定进行制度改革:重新分配房子.这可是一件大事 ...

  7. [kuangbin带你飞]专题十 匹配问题 二分图最大权匹配

    二分图最大权匹配有km算法和网络流算法 km算法模板默认解决最大权匹配的问题 而使用最小费用最大流 是解决最小权匹配问题 这两种办法都可以求最大最小权 需要两次取反 TAT 感觉讲km会很难的样子.. ...

  8. uoj#80 二分图最大权匹配

    题意:给定二分图,有边权,求最大边权匹配.边权非负. 解:KM算法求解最大权完备匹配. 完备匹配就是点数少的那一边每个点都有匹配. 为了让完备匹配与最大权匹配等价,我们添加若干条0边使之成为完全二分图 ...

  9. hdu2255 奔小康赚大钱,最大权匹配,KM算法

    点击打开链接 最大权匹配 KM算法 算法步骤: 设顶点Xi的顶标为a[i],顶点Yi的顶标为b[i] ⅰ.初始时.a[i]为与Xi相关联的边的最大权值.b[j]=0.保证a[i]+b[j]>=w ...

随机推荐

  1. bzoj 1185 旋转卡壳 最小矩形覆盖

    题目大意 就是求一个最小矩形覆盖,逆时针输出其上面的点 这里可以看出,那个最小的矩形覆盖必然有一条边经过其中凸包上的两个点,另外三条边必然至少经过其中一个点,而这样的每一个点逆时针走一遍都满足单调性 ...

  2. <转>提高iOS开发效率的方法和工具

    介绍 这篇文章主要是介绍一下我在iOS开发中使用到的一些可以提升开发效率的方法和工具. IDE 首先要说的肯定是IDE了,说到IDE,Xcode不能跑,当然你也可能同时在使用AppCode等其他的ID ...

  3. UTF-8 有BOM和无BOM

    BOM(byte order mark)是为 UTF-16 和 UTF-32 准备的,用于标记字节序(byte order).微软在 UTF-8 中使用 BOM 是因为这样可以把 UTF-8 和 AS ...

  4. 对于C#中的一些点滴你真的理解了吗?

    废话不多说看题目,看看我们自己真的理解了吗? 1.如下代码输出的结果是什么? public class A{ public virtual void Func(int  number=10) { Co ...

  5. 按Right-BICEP要求的任务二的测试

    测试方法:Right-BICEP 测试计划: 1.Right-结果是否正确? 2.B-是否所有的边界条件都是正确的? 3.P-是否满足性能要求? 4.是否有乘除法? 5.是否有括号? 6.是否有输出方 ...

  6. python视频教程:十分钟快速入门python

    想要学习python这门语言,却始终找不到一个全面的Python视频教程,倘若你是真心想学好一门语言,小编建议你亲自动手实践的.下面来看看入门python的学习教程. Python的语言特性 Pyth ...

  7. 关于java的static语句块

    声明:转载请注明出处 static{}(即static块),会在类被加载的时候执行且仅会被执行一次,一般用来初始化静态变量和调用静态方法,下面我们详细的讨论一下该语句块的特性及应用. 一.在程序的一次 ...

  8. (转)mysql各个主要版本之间的差异

    原文:http://blog.csdn.net/z1988316/article/details/8095407   一.各版本的常用命令差异 show innodb status\G mysql-5 ...

  9. hdu 2081

    PS:...找到好多水题.... #include "stdio.h" int main(){ ]; int i,j,n,N; scanf("%d",& ...

  10. 统计文件夹下java代码行数的小程序--主要是学习任务队列的思想

    首先感谢czbk的老师,录制的视频,让我们有这么好的学习资料.……—— 统计文件夹java文件的行数,首先想到的肯定是用递归的方法,因为文件夹下面可能包含文件夹,用递归的方法,代码容易写.(这和写简单 ...