带权二分图——KM算法hdu2255 poj3565
进阶指南的板子好像有点问题。。交到hdu上会T
需要了解的一些概念:
交错树,顶标,修改量
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define INF 99999999
#define maxn 305 int lx[maxn],ly[maxn];//顶标
int Match[maxn];//记录匹配值
int visx[maxn],visy[maxn];
int w[maxn][maxn];//权值
int slack[maxn];//slack为修改量
int ans,n; bool findPath(int x){
visx[x]=;
for(int y=; y<=n; y++){
if(visy[y])continue;
if(w[x][y]==lx[x]+ly[y]){//如果是相等子图则加入交错树中
visy[y]=;
if(!Match[y]||findPath(Match[y])){//增广后不用再考虑交错树
Match[y]=x;
return true;
}
}
else//不能加入交错树中的点,用来更新修改量
slack[y]=min(slack[y],lx[x]+ly[y]-w[x][y]);
}
return false;
}
void km(){
memset(Match,,sizeof(Match));
memset(lx,,sizeof(lx));
memset(ly,,sizeof(ly));
for(int i=; i<=n; i++)
for(int j=; j<=n; j++)
lx[i]=max(lx[i],w[i][j]); for(int x=; x<=n; x++){
for(int i=;i<=n;i++)slack[i]=INF;//初始化修改量
while(){
memset(visx,,sizeof(visx));
memset(visy,,sizeof(visy));
if(findPath(x))break;//直到x找到一个匹配点时退出循环
//如果没找到匹配点(增广失败),那么找最小修改量,
int tmp=INF;
for(int i=;i<=n;i++){
if(!visy[i]){
if(tmp>slack[i])
tmp=slack[i];
}
}
//更新交错树中的顶标
for(int i=; i<=n; i++){
if(visx[i]) lx[i]-=tmp;
if(visy[i]) ly[i]+=tmp;else slack[i]-=tmp;
}
}
}
}
int main(){
while(scanf("%d",&n)!=EOF){
ans=;
for(int i=; i<=n; i++)
for(int j=; j<=n; j++)
scanf("%d",&w[i][j]);
km();
for(int i=; i<=n; i++)
ans+=w[Match[i]][i];
printf("%d\n",ans);
}
return ;
}
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int MAXN = ;
const double INF = 0xffffffffffff;
const double eps = 1e-; struct Node
{
double x,y;
}Dot1[MAXN],Dot2[MAXN]; double Dist(Node a,Node b)
{
return -sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
} int N,NX,NY;
double Map[MAXN][MAXN];
int link[MAXN];
double lx[MAXN],ly[MAXN],slack[MAXN];
int visx[MAXN],visy[MAXN]; int FindPath(int u)
{
visx[u] = ;
for(int i = ; i <= NY; ++i)
{
if(visy[i])
continue;
double temp = lx[u] + ly[i] - Map[u][i];
if(fabs(temp) <= eps)
{
visy[i] = ;
if(link[i] == - || FindPath(link[i]))
{
link[i] = u;
return ;
}
}
else
{
if(slack[i] > temp)
slack[i] = temp;
}
}
return ;
} void KM()
{
memset(lx,,sizeof(lx));
memset(ly,,sizeof(ly));
memset(link,-,sizeof(link));
for(int i = ; i <= NX; ++i)
{
lx[i] = -INF;
for(int j = ; j <= NY; ++j)
if(Map[i][j] > lx[i])
lx[i] = Map[i][j];
} for(int i = ; i <= NX; ++i)
{
for(int j = ; j <= NY; ++j)
slack[j] = INF;
while()
{
memset(visx,,sizeof(visx));
memset(visy,,sizeof(visy));
if(FindPath(i))
break;
double d = INF;
for(int j = ; j <= NY; ++j)
if(!visy[j] && d > slack[j])
d = slack[j];
for(int j = ; j <= NX; ++j)
if(visx[j])
lx[j] -= d;
for(int j = ; j <= NY; ++j)
{
if(visy[j])
ly[j] += d;
else
slack[j] -= d;
}
}
}
} int main()
{
int N;
while(~scanf("%d",&N))
{
memset(Map,,sizeof(Map));
for(int i = ; i <= N; ++i)
scanf("%lf%lf",&Dot1[i].x,&Dot1[i].y);
for(int i = ; i <= N; ++i)
scanf("%lf%lf",&Dot2[i].x,&Dot2[i].y); for(int i = ; i <= N; ++i)
for(int j = ; j <= N; ++j)
Map[i][j] = Dist(Dot1[i],Dot2[j]); NX = NY = N;
KM();
for(int i = ; i <= N; ++i)
{
for(int j = ; j <= N; ++j)
{
if(link[j] == i)
{
printf("%d\n",j);
break;
}
}
}
} return ;
}
带权二分图——KM算法hdu2255 poj3565的更多相关文章
- POJ3565带权匹配——km算法
题目:http://poj.org/problem?id=3565 神奇结论:当总边权最小时,任意两条边不相交! 转化为求二分图带权最小匹配. 可以用费用流做.但这里学一下km算法. https:// ...
- KM(Kuhn-Munkres)算法求带权二分图的最佳匹配
KM(Kuhn-Munkres)算法求带权二分图的最佳匹配 相关概念 这个算法个人觉得一开始时有点难以理解它的一些概念,特别是新定义出来的,因为不知道是干嘛用的.但是,在了解了算法的执行过程和原理后, ...
- 运动员最佳匹配问题 KM算法:带权二分图匹配
题面: 羽毛球队有男女运动员各n人.给定2 个n×n矩阵P和Q.P[i][j]是男运动员i和女运动员j配对组成混合双打的男运动员竞赛优势:Q[i][j]是女运动员i和男运动员j配合的女运动员竞赛优势. ...
- HDU 2255 奔小康赚大钱(带权二分图最大匹配)
HDU 2255 奔小康赚大钱(带权二分图最大匹配) Description 传说在遥远的地方有一个非常富裕的村落,有一天,村长决定进行制度改革:重新分配房子. 这可是一件大事,关系到人民的住房问题啊 ...
- POJ 2195 Going Home (带权二分图匹配)
POJ 2195 Going Home (带权二分图匹配) Description On a grid map there are n little men and n houses. In each ...
- Luogu 1559 运动员最佳匹配问题(带权二分图最大匹配)
Luogu 1559 运动员最佳匹配问题(带权二分图最大匹配) Description 羽毛球队有男女运动员各n人.给定2 个n×n矩阵P和Q.P[i][j]是男运动员i和女运动员j配对组成混合双打的 ...
- Glorious Brilliance (最短路 + 带权二分图匹配)
这是一道代码大题.一开始读错题意了,然后理解成直接看上去的那种相邻,然后想不通好久!!! 把不同联通的图分离出来,然后先预处理一下形成之后的相邻图的状态,然后根据01确定哪一些是需要更换状态的,然后建 ...
- [HAOI2008]移动玩具(状压&带权二分图)
题目描述 • 一个 4 × 4 的 0/1 矩阵 • 每次可以交换相邻两个元素 • 求从初始状态到目标状态的最小交换次数 输入格式 前四行,每行一个长为 4 的 0/1 字符串,描述初始状态. 后四行 ...
- POJ 2195 Going Home | 带权二分图匹配
给个地图有人和房子 保证人==房子,每个人移动到房子处需要花费曼哈顿距离的代价 问让人都住在房子里最小代价 显然是个带权二分图最大匹配 转化成以一个网络,规定w是容量,c是代价 1.S向人连边,w=1 ...
随机推荐
- ECMAScript1.2 表达式|语句|break|continue
表达式 一个表达式可以产生一个值,有可能是运算,函数调用, 有可能是字面量,表达式可以放在任何需要值的地方. 语句 语句可以理解为一个行为,循环语句和判断语句就是典型的语句. 一个程序有很多个语句组成 ...
- kettle 中 java.lang.ClassCastException: [B cannot be cast to java.lang.String报错的解决方法
问题描述:从数据库中查询出的某字段是json类型数据,然后在json输入步骤报错java.lang.ClassCastException: [B cannot be cast to java.lang ...
- Error resolving template,template might not exist or might not be accessible by any of the configured Template Resolvers
template might not exist or might not be accessible by any of the configured Template Resolvers at o ...
- Number浮点数运算详解
文章来自我的 github 博客,包括技术输出和学习笔记,欢迎star. 一道题 0.1 + 0.2 = ? 在浏览器中测试下计算结果,得到的结果是 0.30000000000000004,并不是理想 ...
- JS对象 向上取整ceil() ceil() 方法可对一个数进行向上取整。 语法: Math.ceil(x) 注意:它返回的是大于或等于x,并且与x最接近的整数。
向上取整ceil() ceil() 方法可对一个数进行向上取整. 语法: Math.ceil(x) 参数说明: 注意:它返回的是大于或等于x,并且与x最接近的整数. 我们将把 ceil() 方法运用到 ...
- Got permission denied while trying to connect to the Docker daemon
答案:https://stackoverflow.com/questions/48568172/docker-sock-permission-denied
- [JZOJ3690] 【CF418D】Big Problems for Organizers
题目 题目大意 给你一棵树,然后有一堆询问,每次给出两个点. 问所有点到两个点中最近点的距离的最大值. 正解 本来打了倍增,然后爆了,也懒得调-- 显然可以在两个点之间的路径的中点处割开,一边归一个点 ...
- 廖雪峰Java16函数式编程-2Stream-7其他操作
1. 排序 Stream<T> sorted(); //按元素默认大小排序(必须实现Comparable接口) Stream<T> sorted(Comparator<? ...
- 免费带你体验阿里巴巴旗舰大数据计算产品MaxCompute
什么是MaxCompute? 众所周知,MaxCompute是阿里云推出的承载EB级的数据存储能力,百PB级的单日计算能力,公共云覆盖国内外十几个国家和地区,专有云包含城市大脑在内部署超过100+套的 ...
- Kunbernetes从私有仓库nexus拉取镜像
1.docker登陆认证 [root@master ~]# vim /etc/docker/daemon.json { "insecure-registries": [" ...