KM算法:
hdu2255 (大概理解了 参考博客: http://blog.csdn.net/niushuai666/article/details/7171880)
         所谓交错树:就是已经匹配好的。(我自己理解的)
         交错树中的X集合和不在交错树中的Y集合去找:d=min(lx[i]-map[i][j]); 然后交错树中的x顶点-d,交错树中的Y顶点+d;
         其实核心还是逐步找最优解的过程。
         还有一个知识点:

    Tutte定理:一个图G有完备匹配,其充要条件是,对于图中任意点集U,去掉U后剩下的具有奇数个顶点的连通分量个数(记作o(G-U))不超过U中的顶点数。。
         若由二分图中所有满足A[i]+B[j]=w[i,j]的边(i,j)构成的子图(称做相等子图(概念很重要))有完备匹配,那么这个完备匹配就是二分图的最大权匹配。
                 (理解性记忆的,我现在也就能理解到这个水平了)
                 还有kuangbin大哥写的KM博客: http://www.cnblogs.com/kuangbin/archive/2012/08/19/2646535.html

       hdu2255 题解:http://blog.csdn.net/niushuai666/article/details/7171525

Problem Description

传说在遥远的地方有一个非常富裕的村落,有一天,村长决定进行制度改革:重新分配房子。
这可是一件大事,关系到人民的住房问题啊。村里共有n间房间,刚好有n家老百姓,考虑到每家都要有房住(如果有老百姓没房子住的话,容易引起不安定因素),每家必须分配到一间房子且只能得到一间房子。
另一方面,村长和另外的村领导希望得到最大的效益,这样村里的机构才会有钱.由于老百姓都比较富裕,他们都能对每一间房子在他们的经济范围内出一定的价格,比如有3间房子,一家老百姓可以对第一间出10万,对第2间出2万,对第3间出20万.(当然是在他们的经济范围内).现在这个问题就是村领导怎样分配房子才能使收入最大.(村民即使有钱购买一间房子但不一定能买到,要看村领导分配的).

Input

输入数据包含多组测试用例,每组数据的第一行输入n,表示房子的数量(也是老百姓家的数量),接下来有n行,每行n个数表示第i个村名对第j间房出的价格(n<=300)。

Output

请对每组数据输出最大的收入值,每组的输出占一行。

Sample Input

2

100 10

15 23

Sample Output

123

AC代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
#define INF 0xfffffff int map[][];
int x[],y[];
int vx[],vy[];
int p[];
int n; int Find(int A)
{
vx[A]=;
for(int i=; i<=n; i++)
{
if(!vy[i] && map[A][i]==x[A]+y[i])
{
vy[i]=;
if(p[i]==- || Find(p[i]))
{
p[i]=A;
return ;
}
}
}
return ;
} void KM()
{
memset(x,,sizeof(x));
memset(y,,sizeof(y));
for(int i=; i<=n; i++)
for(int j=; j<=n; j++)
x[i]=max(x[i],map[i][j]);
for(int i=; i<=n; i++)
{
while()
{
memset(vx,,sizeof(vx));
memset(vy,,sizeof(vy));
if(Find(i))
break;
else
{
int m=INF;
for(int j=; j<=n; j++)
if(vx[j])
for(int k=; k<=n; k++)
if(!vy[k] && m>x[j]+y[k]-map[j][k])
m=x[j]+y[k]-map[j][k];
for(int j=; j<=n; j++)
{
if(vx[j]) x[j]-=m;
if(vy[j]) y[j]+=m;
}
}
}
}
} int main()
{
while(scanf("%d",&n)==)
{
for(int i=; i<=n; i++)
for(int j=; j<=n; j++)
scanf("%d",&map[i][j]);
int ans=;
memset(p,-,sizeof(p));
KM();
for(int i=; i<=n; i++)
ans+=map[p[i]][i];
printf("%d\n",ans);
}
return ;
}

KM标码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<climits>
#include<algorithm>
using namespace std;
#define N 310
int map[N][N];
bool visitx[N], visity[N];
int lx[N],ly[N];
int match[N];
int n; bool Hungary(int u) //匈牙利算法
{
visitx[u]=true;
for(int i=; i<n; i++)
{
if(!visity[i] && lx[u]+ly[i]==map[u][i])
{
visity[i]=true;
if(match[i]==- || Hungary(match[i]))
{
match[i]=u;
return true;
}
}
}
return false;
} void KM_perfect_match()
{
int temp;
memset(lx,,sizeof(lx)); //初始化顶标
memset(ly,,sizeof(ly)); //ly[i]为0
for(int i=; i<n; i++) //lx[i]为权值最大的边
for(int j=; j<n; j++)
lx[i]=max(lx[i],map[i][j]);
for(int i = ; i < n; ++i) //对n个点匹配
{
while()
{
memset(visitx,false,sizeof(visitx));
memset(visity,false,sizeof(visity));
if(Hungary(i)) //匹配成功
break;
else //匹配失败,找最小值
{
temp=INT_MAX;
for(int j=; j<n; j++) //x在交错树中
if(visitx[j])
for(int k=; k<n; ++k) //y在交错树外
if(!visity[k] && temp>lx[j]+ly[k]-map[j][k])
temp=lx[j]+ly[k]-map[j][k];
for(int j=; j<n; j++) //更新顶标
{
if(visitx[j]) lx[j]-=temp;
if(visity[j]) ly[j]+=temp;
}
}
}
}
} int main()
{
int ans;
while(scanf("%d",&n)!=EOF)
{
ans=;
memset(match,-,sizeof(match));
for(int i=; i<n; i++)
for(int j=; j<n; j++)
scanf("%d",&map[i][j]);
KM_perfect_match();
for(int i=; i<n; i++) //权值相加
ans+=map[match[i]][i];
printf("%d\n",ans);
}
return ;
}

优化的KM:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<climits>
#include<algorithm>
using namespace std;
#define N 310
int map[N][N];
bool visitx[N], visity[N];
int lx[N],ly[N];
int slack[N];
int match[N];
int n; int Scan() //输入外挂
{
int res=,ch;
while(!((ch=getchar())>='' && ch<='' ) )
if(ch==EOF) return << ;
res=ch-'';
while((ch=getchar())>=''&&ch<='')
res=res*+(ch-'') ;
return res;
} bool Hungary(int u) //匈牙利算法
{
visitx[u]=true;
for(int i=; i<n; i++)
{
if(visity[i])
continue;
if(lx[u]+ly[i]==map[u][i])
{
visity[i]=true;
if(match[i]==-||Hungary(match[i]))
{
match[i]=u;
return true;
}
}
else //不在相等子图
slack[i]=min(slack[i], lx[u] + ly[i] - map[u][i]);
}
return false;
} void KM_perfect_match()
{
int temp;
memset(lx,,sizeof(lx)); //初始化顶标
memset(ly,,sizeof(ly)); //ly[i]为0
for(int i=; i<n; i++) //lx[i]为权值最大的边
for(int j=; j<n; j++)
lx[i]=max(lx[i],map[i][j]);
for(int i=; i<n; i++) //对n个点匹配
{
for(int j=; j<n; j++)
slack[j]=INT_MAX;
while()
{
memset(visitx,false,sizeof(visitx));
memset(visity,false,sizeof(visity));
if(Hungary(i)) //匹配成功
break;
else //匹配失败,找最小值
{
temp=INT_MAX;
for(int j=; j<n; ++j)
if(!visity[j])
if(temp>slack[j])
temp=slack[j];
for(int j=; j<n; j++) //更新顶标
{
if(visitx[j]) lx[j]-=temp;
if(visity[j]) ly[j]+=temp;
else slack[j]-=temp;
}
}
}
}
} int main()
{
int ans;
while(scanf("%d",&n)!=EOF)
{
ans=;
memset(match,-,sizeof(match));
for(int i=; i<n; i++)
for(int j=; j<n; j++)
map[i][j]=Scan();
KM_perfect_match();
for(int i=; i<n; ++i) //权值相加
ans+=map[match[i]][i];
printf("%d\n",ans);
}
return ;
}

hdu2255 二分图最大权配KM的更多相关文章

  1. Hdu2255 奔小康赚大钱(二分图最大权匹配KM算法)

    奔小康赚大钱 Problem Description 传说在遥远的地方有一个非常富裕的村落,有一天,村长决定进行制度改革:重新分配房子. 这可是一件大事,关系到人民的住房问题啊.村里共有n间房间,刚好 ...

  2. HDU2255 奔小康赚大钱 —— 二分图最大权匹配 KM算法

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2255 奔小康赚大钱 Time Limit: 1000/1000 MS (Java/Others)    ...

  3. 二分图最大权匹配——KM算法

    前言 这东西虽然我早就学过了,但是最近才发现我以前学的是假的,心中感慨万千(雾),故作此篇. 简介 带权二分图:每条边都有权值的二分图 最大权匹配:使所选边权和最大的匹配 KM算法,全称Kuhn-Mu ...

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

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

  5. HDU3488 Tour —— 二分图最大权匹配 KM算法

    题目链接:https://vjudge.net/problem/HDU-3488 Tour Time Limit: 3000/1000 MS (Java/Others)    Memory Limit ...

  6. Uvalive 4043 Ants —— 二分图最大权匹配 KM算法

    题目链接:https://vjudge.net/problem/UVALive-4043 题意: 给出n个白点和n个黑点的坐标, 要求用n条不相交的线段把他们连接起来,其中每条线段恰好连接一个白点和黑 ...

  7. 【模板】二分图最大权完美匹配KM算法

    hdu2255模板题 KM是什么意思,详见百度百科. 总之知道它可以求二分图最大权完美匹配就可以了,时间复杂度为O(n^3). 给张图. 二分图有了边权,求最大匹配下的最大权值. 所以该怎么做呢?对啊 ...

  8. 二分图最大权值匹配 KM算法 模板

    KM算法详解+模板 大佬讲的太好了!!!太好了!!! 转载自:http://www.cnblogs.com/wenruo/p/5264235.html KM算法用来求二分图最大权完美匹配. 本文配合该 ...

  9. HDU2255-奔小康赚大钱-二分图最大权值匹配-KM算法

    二分图最大权值匹配问题.用KM算法. 最小权值的时候把权值设置成相反数 /*-------------------------------------------------------------- ...

随机推荐

  1. Greedy:Physics Experiment(弹性碰撞模型)(POJ 3848)

    物理实验 题目大意:有一个与地面垂直的管子,管口与地面相距H,管子里面有很多弹性球,从t=0时,第一个球从管口求开始下落,然后每1s就会又有球从球当前位置开始下落,球碰到地面原速返回,球与球之间相碰会 ...

  2. oracle触发器加条件判断

    oracle触发器加条件判断,如果某个字段,isnode=0,那么不执行下面的方法,数据如下: create or replace trigger tr_basestation_insert_emp ...

  3. unbutu下搭建FTP服务

    安装 apt-get install vsftpd 启动 service vsftpd start 第一次连接的时候出了点问题,报了一个 login incorrect 530的连接错误 然后百度了一 ...

  4. 【leetcode】Jump Game I & II (hard)

    Jump Game (middle) Given an array of non-negative integers, you are initially positioned at the firs ...

  5. IOS - UIViewController的生命周期

    1)Load周期 2)Unload周期 在UIViewController中,view(黑体的view指的是controller的view属性)有两个循环:加载和卸载循环.当程序的一部分向contro ...

  6. 数据库的日志数据库(_log.ldf)文件太大,如何压缩

    DUMP TRANSACTION TCB WITH NO_LOGBACKUP LOG TCB WITH NO_LOGDBCC SHRINKDATABASE(TCB) 执行这三条语句就可以了,这里的TC ...

  7. asp.net Excel数据导入到数据库中

    protected void Btn_Import_Click(object sender, EventArgs e) { bool Result_Import = false; bool Resul ...

  8. 使用Apache+Dreamweaver(或者H-builder)搭建php开发环境

    使用得工具说明 php+Apache服务器+Dreamweaver+mysql数据库 下载安装好wamp,可以在网上直接百度下载,为了方便,我给放个百度云的链接.wamp下载:链接:http://pa ...

  9. C# 中的Singleton模式

    一般写Singleton基本都是一下这个套路 class Singleton { public static Singleton instance; private Singleton() { } p ...

  10. 无废话Android之activity的生命周期、activity的启动模式、activity横竖屏切换的生命周期、开启新的activity获取他的返回值、利用广播实现ip拨号、短信接收广播、短信监听器(6)

    1.activity的生命周期 这七个方法定义了Activity的完整生命周期.实现这些方法可以帮助我们监视其中的三个嵌套生命周期循环: (1)Activity的完整生命周期 自第一次调用onCrea ...