Luogu 1559 运动员最佳匹配问题(带权二分图最大匹配)
Luogu 1559 运动员最佳匹配问题(带权二分图最大匹配)
Description
羽毛球队有男女运动员各n人。给定2 个n×n矩阵P和Q。P[i][j]是男运动员i和女运动员j配对组成混合双打的男运动员竞赛优势;Q[i][j]是女运动员i和男运动员j配合的女运动员竞赛优势。由于技术配合和心理状态等各种因素影响,P[i][j]不一定等于Q[j][i]。男运动员i和女运动员j配对组成混合双打的男女双方竞赛优势为P[i][j]*Q[j][i]。设计一个算法,计算男女运动员最佳配对法,使各组男女双方竞赛优势的总和达到最大。
Input
第一行有1 个正整数n (1≤n≤20)。接下来的2n行,每行n个数。前n行是p,后n行是q。
Output
将计算出的男女双方竞赛优势的总和的最大值输出。
Sample Input
3
10 2 3
2 3 4
3 4 5
2 2 2
3 5 3
4 5 1
Sample Output
52
Http
Luogu:https://www.luogu.org/problem/show?pid=1559#sub
Source
带权二分图的最大匹配
解决思路
这个题目是一道带权二分图最大匹配的题目,我们要用到的就是KM算法。
那么什么是KM算法呢?
通俗点来讲,KM算法就是给匈牙利算法提供一张图,让后者去匹配。
KM算法是基于贪心的思想,选取权值最大的边建图,然后让匈牙利算法去判断其可行性。
我们知道,匈牙利算法的关键就是“让”出边来匹配,那么KM算法的关键就是如何建出这张图。
接下来我们结合代码来看一看。
首先我们对代码中的变量进行一下说明,我们定义二分图的左边这一组为
X,右边一组为Y。定义use_left,use_right分别标记左边或右边的点是否标记,同时标记其是否在增广路中。定义Wx,Wy分别为左边和右边的顶标这是KM算法的关键之处。这个顶标是用来干嘛的呢?这就是用来判断某一条边是否在我们定义的图中的。我们定义只有满足Wx[i]+Wy[j]==W[i][j]的这样一条边i->j才在图中存在。所以初始化的时候,Wx[i]置为从i出发的最大边的权值,而Wy[j]置为0。这就相当于把i->j这条边加入图中。
对于每一个左边的点i,我们首先对其跑一边匈牙利算法,如果发现无法匹配,则进行下面的操作。从剩余的边中选一条出发点i已标记而到达点j未标记(标记操作在匈牙利算法中实现),并满足Wx[i]+Wy[j]-W[i][j]最小。选择这条边,然后把所有已标记的左边的点的Wx加上W[i][j],而右边的已标记的点的Wy分别减去W[i][j]。这相当于把i->j这条边加入到我们要判断的图中,并且原来图中有的边不变。(仔细想一想,结合我们判断某条边是否在图中的方法:Wx[i]+Wy[j]==W[i][j])
推荐一篇关于二分图匹配的KM算法的文章:http://www.cnblogs.com/Lanly/p/6291214.html
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
#define mem(Arr,x) memset(Arr,x,sizeof(Arr))
class EDGE
{
public:
int v,w;
};
const int maxN=30;
const int inf=2147483647;
int n;
vector<EDGE> E[maxN];//存二分图的边
int Match[maxN];//存右边匹配的左点编号
bool use_left[maxN];//判断是否访问,一是避免重复,二十判断是否在增广路上,以便后面加边
bool use_right[maxN];
int Wx[maxN];//两边的顶标
int Wy[maxN];
int read();
bool Hungary(int u);
int main()
{
int P[maxN][maxN];
int Q[maxN][maxN];
mem(Match,-1);
mem(Wy,0);
cin>>n;
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
P[i][j]=read();
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
Q[i][j]=read();
for (int i=1;i<=n;i++)
{
int D=-inf;//初始化左边的顶标
for (int j=1;j<=n;j++)
{
E[i].push_back((EDGE){j,P[i][j]*Q[j][i]});
D=max(D,P[i][j]*Q[j][i]);//预处理出Wx
}
Wx[i]=D;
Wy[i]=0;
}
for (int i=1;i<=n;i++)
{
do
{
mem(use_left,0);
mem(use_right,0);
if (Hungary(i))
break;
int D=inf;
for (int j=1;j<=n;j++)
if (use_left[j]==1)
{
for (int k=0;k<E[j].size();k++)
{
int v=E[j][k].v;
int w=E[j][k].w;
if (use_right[v]==0)
{
D=min(D,Wx[j]+Wy[v]-w);
}
}
}
for (int j=1;j<=n;j++)
if (use_left[j])
Wx[j]=Wx[j]-D;
for (int j=1;j<=n;j++)
if (use_right[j])
Wy[j]=Wy[j]+D;
}
while (1);
}
int Ans=0;
for (int i=1;i<=n;i++)
for (int j=0;j<E[Match[i]].size();j++)
{
if (E[Match[i]][j].v==i)
{
Ans+=E[Match[i]][j].w;
break;
}
}
cout<<Ans<<endl;
return 0;
}
int read()//读入优化
{
int x=0;
int k=1;
char ch=getchar();
while (((ch>'9')||(ch<'0'))&&(ch!='-'))
ch=getchar();
if (ch=='-')
{
k=-1;
ch=getchar();
}
while ((ch<='9')&&(ch>='0'))
{
x=x*10+ch-48;
ch=getchar();
}
return x*k;
}
bool Hungary(int u)//匈牙利算法判断
{
use_left[u]=1;
for (int i=0;i<E[u].size();i++)
{
int v=E[u][i].v;
if ((use_right[v]==0)&&(Wx[u]+Wy[v]==E[u][i].w))
{
use_right[v]=1;
if ((Match[v]==-1) || (Hungary(Match[v])) )
{
Match[v]=u;
return 1;
}
}
}
return 0;
}
Luogu 1559 运动员最佳匹配问题(带权二分图最大匹配)的更多相关文章
- [Luogu 1559]运动员最佳匹配问题
Description 题库链接 求 \(2\times N\) 个点的带权二分图最佳匹配. \(1\leq N\leq 20\) Solution 我还是太菜了啊...到现在才学 \(KM\) . ...
- HDU 2255 奔小康赚大钱(带权二分图最大匹配)
HDU 2255 奔小康赚大钱(带权二分图最大匹配) Description 传说在遥远的地方有一个非常富裕的村落,有一天,村长决定进行制度改革:重新分配房子. 这可是一件大事,关系到人民的住房问题啊 ...
- UVA1349(带权二分图最大匹配 --> KM算法模板)
UVA1349 题意:给定一些有向带权边,求出把这些边构造成一个个环,总权值最小 解法: 对于带权的二分图的匹配问题可以用通过KM算法求解. 要求最大权匹配就是初始化g[i][j]为0,直接跑就可以: ...
- "《算法导论》之‘图’":不带权二分图最大匹配(匈牙利算法)
博文“二分图的最大匹配.完美匹配和匈牙利算法”对二分图相关的几个概念讲的特别形象,特别容易理解.本文介绍部分主要摘自此博文. 还有其他可参考博文: 趣写算法系列之--匈牙利算法 用于二分图匹配的匈牙利 ...
- KM模板 最大权匹配(广搜版) Luogu P1559 运动员最佳匹配问题
KM板题: #include <bits/stdc++.h> using namespace std; inline void read(int &num) { char ch; ...
- 带权二分图最大匹配KM算法
二分图的判定 如果一个图是连通的,可以用如下的染色法判定是否二分图: 我们把X部的结点颜色设为0,Y部的颜色设为1. 从某个未染色的结点u开始,做BFS或者DFS .把u染为0,枚举u的儿子v.如果v ...
- POJ 2195 Going Home | 带权二分图匹配
给个地图有人和房子 保证人==房子,每个人移动到房子处需要花费曼哈顿距离的代价 问让人都住在房子里最小代价 显然是个带权二分图最大匹配 转化成以一个网络,规定w是容量,c是代价 1.S向人连边,w=1 ...
- 运动员最佳匹配问题 KM算法:带权二分图匹配
题面: 羽毛球队有男女运动员各n人.给定2 个n×n矩阵P和Q.P[i][j]是男运动员i和女运动员j配对组成混合双打的男运动员竞赛优势:Q[i][j]是女运动员i和男运动员j配合的女运动员竞赛优势. ...
- KM(Kuhn-Munkres)算法求带权二分图的最佳匹配
KM(Kuhn-Munkres)算法求带权二分图的最佳匹配 相关概念 这个算法个人觉得一开始时有点难以理解它的一些概念,特别是新定义出来的,因为不知道是干嘛用的.但是,在了解了算法的执行过程和原理后, ...
随机推荐
- Java中的会话管理——HttpServlet,Cookies,URL Rewriting(译)
参考谷歌翻译,关键字直接使用英文,原文地址:http://www.journaldev.com/1907/java-session-management-servlet-httpsession-url ...
- 使用Mingw编译wxSqlite3-3.0.5
最近在学习wxWidgets,而且官方也出了3.0版本,貌似还不错的样子,准备做个小程序来练手.中间需要用到数据库看到很多人推荐wxSqlite3就去下来看看,以下是我使用TDM-GCC 4.8.1( ...
- 跨域请求,jsonp
其实跨域请求,只需要在请求的url后面加上callback=?即可. 提供以下两种获取跨域的ajax的写法,都是基于jQuery.都已经成功使用,兼容做到ie7,(ie6未测试);案例地址来自豆瓣开放 ...
- 遇到bug我会怎么做
我今天遇到一个问题,ztree显示数据,本来这个功能是没有问题的,但是当我新加入了几个页面筛选条件时,将集合传入ztree ,页面缺一直没显示出来,弄了两个小时,代码我都仔细排查了一次,发现没有问题, ...
- 高防TTCDN
TCDN是深圳市云中漫网络科技公司高防CDN产品的品牌名称,既可以防御,也可以达到加速的效果,价格实惠.TTCDN适用于WEB应用,可以隐藏源站服务器IP,有效的减轻源站服务器压力,加快全国各地区线路 ...
- 解决Linux下面Firefox无法播放mp3的问题
之前一直使用kali linux ,上班屏蔽噪音都用网易音乐.既然没有Linux客户端,那就网页版吧.不得不说,网易音乐的网页版做的真心赞. 在Kali Linux下面使用Firefox听歌一直都很正 ...
- CSS 公共样式
global.css | reset.css(格式化样式) common.css(公共组件样式) layout.css(当前页面样式) 清除全站所有页面的浏览器默认样式,保证在初始样式在所有浏览器下一 ...
- EF之通过不同条件查找去重复
Enumerable.Distinct<TSource> Method(IEnumerable<TSource>, IEqualityComparer<TSource&g ...
- KNN算法介绍
KNN算法全名为k-Nearest Neighbor,就是K最近邻的意思. 算法描述 KNN是一种分类算法,其基本思想是采用测量不同特征值之间的距离方法进行分类. 算法过程如下: 1.准备样本数据集( ...
- RELabel : 一个极简的正则表达式匹配和展示框架
html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,bi ...