HDU 3488 Tour (最大权完美匹配)【KM算法】

<题目链接>

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

解题分析

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

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 using namespace std;
 5
 6 const int N =205;
 7 #define mem(a,b) memset(a,b,sizeof(a))
 8 #define rep(i,s,t) for(int i=s;i<=t;i++)
 9 #define INF 0x3f3f3f3f
10 int n,linker[N],w[N][N],lx[N],ly[N],slack[N];
11 int visx[N],visy[N],nx,ny;
12 bool DFS(int x){
13     visx[x]=1;
14     rep(y,1,n){
15         if(visy[y]==1)continue;    //每次只常识匹配一次y,相当于匈牙利中的vis[]
16         int tmp=lx[x]+ly[y]-w[x][y];  //x,y期望值之和与x,y之间的权值的差值
17         if(!tmp){   //x,y之间期望值==他们之间权值时符合要求
18             visy[y]=1;
19             if(linker[y]==-1||DFS(linker[y])){   //y没有归属者,或者y的原始归属者能够找到其他归属者
20                 linker[y]=x;
21                 return true;
22             }
23         }else slack[y]=min(slack[y],tmp);
24     }
25     return false;
26 }
27 int KM(){
28     mem(linker,-1);mem(ly,0);   //初始化,y的期望值为0
29     rep(i,1,nx){     //初始化lx[]数组
30         lx[i]=-INF;
31         for(int j=1;j<=ny;j++){
32             lx[i]=max(lx[i],w[i][j]);   //lx为x的期望值,lx初始化为与它关联边中最大的
33         }
34     }
35     //为每一个x尝试解决归属问题
36     rep(x,1,n){
37         rep(i,1,n)slack[i]=INF;
38         while(true){
39             mem(visx,0);mem(visy,0);
40             if(DFS(x))break;//若成功(找到了增广轨),则该点增广完成,进入下一个点的增广
41             //若失败(没有找到增广轨),则需要改变一些点的标号,使得图中可行边的数量增加。
42             //方法为:将所有在增广轨中(就是在增广过程中遍历到)的X方点的标号全部减去一个常数d,
43             //所有在增广轨中的Y方点的标号全部加上一个常数d
44             int d=INF;
45             rep(i,1,ny)if(!visy[i])d=min(d,slack[i]);   //d为没有匹配到的y的slack中的最小值
46             rep(i,1,nx)if(visx[i])lx[i]-=d;
47             rep(i,1,ny)
48                 if(visy[i])ly[i]+=d;
49                 else slack[i]-=d;      //修改顶标后,要把所有不在交错树中的Y顶点的slack值都减去d
50         }
51     }
52     int res=0;
53     rep(i,1,ny){
54         if(linker[i]!=-1)
55             res+=w[linker[i]][i];
56     }
57     return res;
58 }
59 /*--  以上为KM算法模板   --*/
60 int main(){
61     int T,m,u,v,c;scanf("%d",&T);
62     while(T--){
63         scanf("%d%d",&n,&m);
64         rep(i,1,n) rep(j,1,n){
65             w[i][j]=-INF;
66         }
67         //将每个点进行拆点,分成出度(x部分)和入度(y部分)两部分来处理
68         nx=ny=n;
69         rep(i,1,m){
70             scanf("%d%d%d",&u,&v,&c);
71             if(w[u][v]<-c)    //因为要求最小的权值,而KM算法是求最大的权值,所以这里将所有边的权值取反,这样用KM算出的最大值的相反数就是最小值了
72                 w[u][v]=-c;   //去重边,取权值最小的边
73         }
74         printf("%d\n",-1*KM());   //对求出的最大值取反即可
75     }
76 }

2018-11-18

原文地址:https://www.cnblogs.com/00isok/p/9977664.html

时间: 2024-10-07 06:13:45

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

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

大佬讲的太好了!!!太好了!!! http://www.cnblogs.com/wenruo/p/5264235.html KM算法用来求二分图最大权完美匹配. 本文配合该博文服用更佳:趣写算法系列之--匈牙利算法 本文没有给出KM算法的原理,只是模拟了一遍算法的过程.另,博主水平较差,发现问题欢迎指出,谢谢!!!! 现在有N男N女,有些男生和女生之间互相有好感,我们将其好感程度定义为好感度,我们希望把他们两两配对,并且最后希望好感度和最大. 怎么选择最优的配对方法呢? 首先,每个女生会有一个期

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

Tour In the kingdom of Henryy, there are N (2 <= N <= 200) cities, with M (M <= 30000) one-way roads connecting them. You are lucky enough to have a chance to have a tour in the kingdom. The route should be designed as: The route should contain o

HDU 3722 Card Game(二分图最佳完美匹配+KM算法)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3722 1 /* 2 问题 3 将任意的两个字符串进行匹配,使得匹配后权值和最大 4 5 解题思路 6 将任意的字符串的权值计算出来,使用KM算法即可. 7 */ 8 #include<cstdio> 9 #include<cstring> 10 #include<algorithm> 11 using namespace std; 12 13 const int maxn

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

二分图最大权值匹配问题.用KM算法. 最小权值的时候把权值设置成相反数 1 /*--------------------------------------------------------------------------------------*/ 2 3 #include <algorithm> 4 #include <iostream> 5 #include <cstring> 6 #include <ctype.h> 7 #include &l

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

/** 题目:hdu2255 奔小康赚大钱 km算法 链接:http://acm.hdu.edu.cn/showproblem.php?pid=2255 题意:lv 思路:最优匹配(最大权完美匹配) km算法 模板来自:http://www.cnblogs.com/wenruo/p/5264235.html 如果是求最小权完美匹配,那么将所有权值取相反数,然后求得最大权,输出最大权的相反数即可. */ #include <iostream> #include <cstring> #

Hdu 3488 Tour (KM 有向环覆盖)

题目链接: Hdu 3488 Tour 题目描述: 有n个节点,m条有权单向路,要求用一个或者多个环覆盖所有的节点.每个节点只能出现在一个环中,每个环中至少有两个节点.问最小边权花费为多少? 解题思路: 因为每个节点就出现一个,那么每个节点出度和入度都为1咯.我们可以对每个节点u拆点为u,u',分别放在集合X,Y.然后对两个集合进行完备匹配.完备匹配成功以后,每个节点就会有只有一个出度,一个入度的. 用KM求最小匹配的话,先初始化maps为-INF,然后把各边权值存为负,求出最大值取反即可. 1

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

[文章详解出处]https://www.cnblogs.com/wenruo/p/5264235.html KM算法是用来求二分图最大权完美匹配的.[也就算之前的匈牙利算法求二分最大匹配的变种??] 这里就贴一下模板代码..2333... 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <algorithm> 5 using namespace std; 6

最大权完美匹配:KM算法的优化

KM算法 设二分图的两部分点集分别为 $X=\{X_1, X_2, \ldots, X_n\}$ 和 $Y=\{Y_1, Y_2, \ldots, Y_m\}$, $\left<X_i, Y_j\right>$ 的边权为 $w_{ij}$. 给两部分点集分别赋点权 $\{A_i\}, \{B_i\}$, 使得 $A_i+B_j \ge w_{ij}$. 取等的边的生成子图叫做相等子图.那么相等子图的完美匹配就是最大权匹配.我们需要适当选取权值,使相等子图有完美匹配. 算法流程如下: 令 $X=

HDU_2255 二分图最佳完美匹配 KM匈牙利算法

一开始还没看懂这个算法,后来看了陶叔去年的PPT的实例演示才弄懂 用一个lx[]和ly[]来记录X和Y集合中点的权值,有个定理是 lx[i]+ly[j]==w[i][j](边权值) 则该点是最佳匹配,因为首先 那个不等式肯定要>=的,否则就不满足题意了,如果是>则可以去匹配更有价值的边或者把权值降下来让匹配边的潜力更大. 所以只有把握了这个条件,其他就是走一遍最大匹配数.以及up()函数用来在无法匹配的时候,进行其他点的权值降低(也可以说是增广路的搜索)来得到匹配. #include <