<题目链接>

题目大意:
给出n个点m条单向边边以及经过每条边的费用,让你求出走过一个哈密顿环(除起点外,每个点只能走一次)的最小费用。题目保证至少存在一个环满足条件。

解题分析

因为要求包含所有点一次的环,我们不难发现,这个环中的每个点的出度和入度均为1,所以我们不妨将每个点进行拆点,将所有点的出度和入度分为两部分。因为该环需要包括所有的点,并且题目需要求该环的最小权值,相当于该带权二分图的每个点都需要被覆盖到,由于本题就转化为求该二分图的最优完美匹配问题。二分图的最优匹配问题求解,我们会想到KM算法,但是KM是求最大权完美匹配,所以我们对每个边的权值全部取反,这时候求出的最大权值(该权值<0)的相反数就是最小权值的完美匹配了。

BFS版:

#include <bits/stdc++.h>
using namespace std; typedef long long ll; #define RP(i, s, t) for (int i = s; i <= t; i++)
#define clr(a, b) memset(a, b, sizeof(a)) const int N = ;
const ll INF = 1e18; ll n, wx[N], wy[N], match[N], g[N][N], slk[N], pre[N];
bool viy[N]; void BFS(ll k) {
ll py = , px, yy = , cur;
match[py] = k;
clr(slk, 0x3f); clr(pre, );
do {
px = match[py];
cur = INF;
viy[py] = ;
RP(i, , n)
if (!viy[i]) {
if (wx[px] + wy[i] - g[px][i] < slk[i]) {
slk[i] = wx[px] + wy[i] - g[px][i];
pre[i] = py;
}
if (slk[i] < cur) {
cur = slk[i];
yy = i;
}
}
for (int i = ; i <= n; ++i) {
if (viy[i]) {
wx[match[i]] -= cur;
wy[i] += cur;
} else
slk[i] -= cur;
}
py = yy;
} while (match[py] != ); while (py) {
match[py] = match[pre[py]];
py = pre[py];
}
}
ll KM() {
RP(i, , n) {
wx[i] = , wy[i] = , match[i] = ;
RP(j, , n) wx[i] = max(wx[i], g[i][j]);
}
RP(i, , n) {
clr(viy, );
BFS(i);
}
ll ans = ;
RP(i, , n) ans += wx[match[i]] + wy[i];
return ans;
} int main() {
int T, m, u, v, c;
scanf("%d", &T);
while (T--) {
scanf("%d%d", &n, &m);
RP(i, , n) RP(j, , n) g[i][j] = -INF;
//将每个点进行拆点,分成出度(x部分)和入度(y部分)两部分来处理
RP(i, , m) {
scanf("%d%d%d", &u, &v, &c);
if (g[u][v] < -c) //因为要求最小的权值,而KM算法是求最大的权值,所以这里将所有边的权值取反,这样用KM算出的最大值的相反数就是最小值了
g[u][v] = -c; //去重边,取权值最小的边
}
printf("%lld\n", - * KM()); //对求出的最大值取反即可
}
}

DFS版:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std; const int N =;
#define mem(a,b) memset(a,b,sizeof(a))
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define INF 0x3f3f3f3f
int n,linker[N],w[N][N],lx[N],ly[N],slack[N];
int visx[N],visy[N],nx,ny;
bool DFS(int x){
visx[x]=;
rep(y,,n){
if(visy[y]==)continue; //每次只常识匹配一次y,相当于匈牙利中的vis[]
int tmp=lx[x]+ly[y]-w[x][y]; //x,y期望值之和与x,y之间的权值的差值
if(!tmp){ //x,y之间期望值==他们之间权值时符合要求
visy[y]=;
if(linker[y]==-||DFS(linker[y])){ //y没有归属者,或者y的原始归属者能够找到其他归属者
linker[y]=x;
return true;
}
}else slack[y]=min(slack[y],tmp);
}
return false;
}
int KM(){
mem(linker,-);mem(ly,); //初始化,y的期望值为0
rep(i,,nx){ //初始化lx[]数组
lx[i]=-INF;
for(int j=;j<=ny;j++){
lx[i]=max(lx[i],w[i][j]); //lx为x的期望值,lx初始化为与它关联边中最大的
}
}
//为每一个x尝试解决归属问题
rep(x,,n){
rep(i,,n)slack[i]=INF;
while(true){
mem(visx,);mem(visy,);
if(DFS(x))break;//若成功(找到了增广轨),则该点增广完成,进入下一个点的增广
//若失败(没有找到增广轨),则需要改变一些点的标号,使得图中可行边的数量增加。
//方法为:将所有在增广轨中(就是在增广过程中遍历到)的X方点的标号全部减去一个常数d,
//所有在增广轨中的Y方点的标号全部加上一个常数d
int d=INF;
rep(i,,ny)if(!visy[i])d=min(d,slack[i]); //d为没有匹配到的y的slack中的最小值
rep(i,,nx)if(visx[i])lx[i]-=d;
rep(i,,ny)
if(visy[i])ly[i]+=d;
else slack[i]-=d; //修改顶标后,要把所有不在交错树中的Y顶点的slack值都减去d
}
}
int res=;
rep(i,,ny){
if(linker[i]!=-)
res+=w[linker[i]][i];
}
return res;
}
/*-- 以上为KM算法模板 --*/
int main(){
int T,m,u,v,c;scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
rep(i,,n) rep(j,,n){
w[i][j]=-INF;
}
//将每个点进行拆点,分成出度(x部分)和入度(y部分)两部分来处理
nx=ny=n;
rep(i,,m){
scanf("%d%d%d",&u,&v,&c);
if(w[u][v]<-c) //因为要求最小的权值,而KM算法是求最大的权值,所以这里将所有边的权值取反,这样用KM算出的最大值的相反数就是最小值了
w[u][v]=-c; //去重边,取权值最小的边
}
printf("%d\n",-*KM()); //对求出的最大值取反即可
}
}

HDU 3488 Tour (最大权完美匹配)【KM算法】的更多相关文章

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

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

  2. 二分图最大权完美匹配KM算法

    KM算法二分图 KM求得二分图与普通二分图的不同之处在于:此二分图的每条边(男生女生)上都附了权值(好感度).然后,求怎样完美匹配使得权值之和最大. 这,不止一般的麻烦啊. 可以通过一个期望值来求. ...

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

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

  4. Tour HDU - 3488(最大权值匹配)

    Tour In the kingdom of Henryy, there are N (2 <= N <= 200) cities, with M (M <= 30000) one- ...

  5. 奔小康赚大钱 HDU - 2255(最大权值匹配 KM板题)

    奔小康赚大钱 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Subm ...

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

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

  7. uva 1411 Ants (权值和最小的完美匹配---KM算法)

    uva 1411 Ants Description Young naturalist Bill studies ants in school. His ants feed on plant-louse ...

  8. hdu 3722 二分图 最优完备匹配 KM算法

    这题只要想到是最优完备匹配就行了: 题意:给出n个字符串,若两两相连,将前一个反置添加到后一个后面,相连的值为两个字串从头开始相等的字符个数: 问如何匹配得出最大值: 思路:建图,套模板. 代码: # ...

  9. hdu2255 奔小康赚大钱 km算法解决最优匹配(最大权完美匹配)

    /** 题目:hdu2255 奔小康赚大钱 km算法 链接:http://acm.hdu.edu.cn/showproblem.php?pid=2255 题意:lv 思路:最优匹配(最大权完美匹配) ...

随机推荐

  1. Confluence 6 使用 CSS 样式化 Confluence 的介绍

    这个页面对 Confluence 通过修改 CSS 来改变外观和感觉的情况进行了说明. 层叠样式表(Cascading Style Sheets (CSS))是对 Web 页面进行样式化的工业化标准. ...

  2. Confluence 6 你模板中可用的对象

    包含宏正文和参数,下面的 Confluence 对象在宏中可用: $body 宏的正文(如果宏有正文的话) String $paramfoo, $parambar, ...$param<name ...

  3. SpringBoot的yml配置文件

    1.在src\main\resources下创建application.yml配置文件 spring: datasource: driver-class-name: com.mysql.jdbc.Dr ...

  4. svn上check下来的项目,用idea打开,菜单栏没有svn工具解决办法

    1.用idea打开你的项目(idea已经配置过小乌龟了) 2.菜单栏点击VCS,Enable Version Control Integration... 3.选择Subversion 4.这时候,菜 ...

  5. ubuntu sublime text 3 安装

    #安装GPG wget -qO - https://download.sublimetext.com/sublimehq-pub.gpg | sudo apt-key add - #确保apt被设置为 ...

  6. 安装AngularJS Batarang遇到的问题

    AngularJS Batarang是AngularJS在谷歌浏览器上的一个调试工具,因为国内目前无法访问谷歌浏览器应用商店,所以Batarang只能离线安装.不过在安装这个插件的过程中遇到了一些麻烦 ...

  7. 性能测试四十八:Jenkins+Ant+Jmeter系统部署

    工作步骤: 1.开发提交代码SVN/Git 2.代码编译.打war包 3.上传war包到服务器 4.重启web服务器 5.开始测试/自动化测试 6.发测试结果 Jenkins工作: 1.开发提交代码G ...

  8. loadrunner获取当前日期、明日日期、昨日日期

    DATE_NOW(现在的日期) TIME_NOW(现在的时间) ONE_DAY(一天的时间) ONE_HOUR(一小时的时间) ONE_MIN(一分钟的时间) 可以使用公式获取昨天明天,例如: DAT ...

  9. python unittest套件,修改为失败重新执行

    #套件,修改为失败重新执行 import time import unittest from unittest.suite import _isnotsuite class Suit(unittest ...

  10. jmeter BeanShell实例-----两个变量之间的断言对比

    jmeter BeanShell实例-----两个变量之间的断言对比 在jmeter的中,断言没法对两个变量的进行对比后判断,只能使用Bean Shell断言来进行,总是有人来问怎么写呢.这里写一个简 ...