为什么可以这样拆点在 这道题 都已经证明过

代码:

  1 //题目上面说了“The only exception is that the first and the last city should be the same and this city is visited twice.”
2 //我还以为是起点要使用两次,没想到题意就是全部点连接之后出入度都为1
3
4 //题意:有n座城市,m条带权有向边。有人想要游历所有城市,于是制定了计划:游历的路径是一个或者多个环,且所有城市都必须仅存在于一个环中。问怎样设计路线使得总路程最短?
5 //我们可以用最大权匹配去求:
6 //1.对于每个点u,我们拆成u和u'。u代表着出点,在二分图的左侧;u'代表着入点,在二分图的右侧。
7 //2.如果有一条有向边u-->v,那么在二分图中,我们加一条边u-->v',并且权值取反。
8 //
9 //3.利用KM()算法,求出最大权匹配,再将结果取反,即为答案。
10 // 举个三个点的例子
11 // p->q`->q->r`->r->p`
12 //
13 //问:为何KM()算法求出来的就一定是一个或多个环呢?
14 //1.可知,题目已经说明了必定有解。那么对应的二分图必定存在完全匹配,完全匹配也必定是最大匹配。
15 //2.我们用KM()算法求出了最大权匹配。根据性质:最大权匹配必定为最大匹配。所以,如果最大匹配是完全匹配,那么最大权匹配也是完全匹配。
16 //3.因为最大权匹配是完全匹配。所以所求出的解必定是一个或多个环。
17 #include<stdio.h>
18 #include<algorithm>
19 #include<string.h>
20 #include<iostream>
21 #include<queue>
22 #include<vector>
23 using namespace std;
24 const int maxn=510;
25 const int INF=0x3f3f3f3f;
26 int n,m;
27 int g[maxn][maxn],link[maxn],matchx[maxn],matchy[maxn];
28 int slack[maxn],visitx[maxn],visity[maxn];
29 int dfs(int x)
30 {
31 visitx[x]=1;
32 for(int i=1;i<=n;++i)
33 {
34 if(visity[i]) continue;
35 int temp=matchx[x]+matchy[i]-g[x][i];
36 if(temp==0)
37 {
38 visity[i]=1;
39 if(link[i]==-1 || dfs(link[i]))
40 {
41 link[i]=x;
42 return 1;
43 }
44 }
45 else slack[i]=min(slack[i],temp);
46 }
47 return 0;
48 }
49 int km()
50 {
51 memset(link,-1,sizeof(link));
52 memset(matchy,0,sizeof(matchy));
53 for(int i=1;i<=n;++i)
54 {
55 matchx[i]=-INF;
56 for(int j=1;j<=n;++j)
57 {
58 matchx[i]=max(matchx[i],g[i][j]);
59 }
60 }
61 for(int x=1;x<=n;++x)
62 {
63 for(int i=1;i<=n;++i)
64 slack[i]=INF;
65 while(1)
66 {
67 memset(visitx,0,sizeof(visitx));
68 memset(visity,0,sizeof(visity));
69 if(dfs(x)) break;
70 int d=INF;
71 for(int i=1;i<=n;++i)
72 if(!visity[i])
73 d=min(d,slack[i]);
74 for(int i=1;i<=n;++i)
75 {
76 if(visitx[i])
77 matchx[i]-=d;
78 }
79 for(int i=1;i<=n;++i)
80 {
81 if(visity[i]) matchy[i]+=d;
82 else slack[i]-=d;
83 }
84 }
85 }
86 int ans=0;
87 for(int i=1;i<=n;++i)
88 {
89 if(link[i]!=-1)
90 ans+=g[link[i]][i];
91 }
92 return ans;
93 }
94 int main()
95 {
96 int t;
97 scanf("%d",&t);
98 while(t--)
99 {
100 scanf("%d%d",&n,&m);
101 memset(g,0,sizeof(g));
102 for(int i=1;i<=n;++i)
103 {
104 for(int j=1;j<=n;++j)
105 {
106 g[i][j]=-INF;
107 }
108 }
109 while(m--)
110 {
111 int u,v,w;
112 scanf("%d%d%d",&u,&v,&w);
113 g[u][v]=max(-w,g[u][v]);
114 }
115 printf("%d\n",-km());
116 }
117 return 0;
118 }

HDU 3488-Tour KM的更多相关文章

  1. Hdu 3488 Tour (KM 有向环覆盖)

    题目链接: Hdu 3488 Tour 题目描述: 有n个节点,m条有权单向路,要求用一个或者多个环覆盖所有的节点.每个节点只能出现在一个环中,每个环中至少有两个节点.问最小边权花费为多少? 解题思路 ...

  2. 图论(二分图,KM算法):HDU 3488 Tour

    Tour Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)Total Submis ...

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

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

  4. HDU - 3488 Tour (KM最优匹配)

    题意:对一个带权有向图,将所有点纳入一个或多个环中,且每个点只出现一次,求其所有环的路径之和最小值. 分析:每个点都只出现一次,那么换个思路想,每个点入度出度都为1.将一个点拆成两个点,一个作为入度点 ...

  5. hdu 3488 Tour

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3488 题意:给你一个N个顶点M条边的带权有向图,要你把该图分成1个或多个不相交的有向环.且所有定点都只 ...

  6. HDU 3488 Tour(最小费用流:有向环最小权值覆盖)

    http://acm.hdu.edu.cn/showproblem.php?pid=3488 题意: 给出n个点和m条边,每条边有距离,把这n个点分成1个或多个环,且每个点只能在一个环中,保证有解. ...

  7. HDU 3488 KM Tour

    参考题解 这题注意有重边.. #include <cstdio> #include <cstring> #include <algorithm> using nam ...

  8. Tour HDU - 3488 有向环最小权值覆盖 费用流

    http://acm.hdu.edu.cn/showproblem.php?pid=3488 给一个无源汇的,带有边权的有向图 让你找出一个最小的哈密顿回路 可以用KM算法写,但是费用流也行 思路 1 ...

  9. hdu 3488(KM算法||最小费用最大流)

    Tour Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)Total Submis ...

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

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

随机推荐

  1. 【数据结构与算法】Java制作一个简单数组类

    bobo老师的玩转算法系列–玩转数据结构 简单记录 文章目录 不要小瞧数组 - 制作一个数组类 1 .使用Java中的数组 数组基础 简单使用 2.二次封装属于我们自己的数组 数组基础 制作属于我们自 ...

  2. 攻防世界 - Misc(一)

    base64÷4: 1.下载附件,是一个.txt文件,打开是一串字符, 666C61677B453333423746443841334238343143413936393945444442413234 ...

  3. Java高并发与多线程(三)-----线程的基本属性和主要方法

    今天,我们开始Java高并发与多线程的第三篇,线程的基本属性和主要方法. [属性] 编号(ID) 类型long 用于标识不同的线程,编号唯一,只存在java虚拟机的一次运行 名称(Name) 类型St ...

  4. C++:I/O流的概念和流类库的结构

    一.C++输入输出包含以下三个方面的内容: 对系统指定的标准设备的输入和输出.即从键盘输入数据,输出到显示器屏幕.这种输入输出称为标准的输入输出,简称标准I/O. 以外存磁盘文件为对象进行输入和输出, ...

  5. USB充电限流IC,可调到4.8A,输入 6V关闭

    随着手机充电电流的提升,和设备的多样化,USB限流芯片就随着需求的增加而越来越多,同时为了更好的保护电子设备,需要进行一路或者多路的负载进行限流. 一般说明 PW1503,PW1502是超低RDS(O ...

  6. Flink 中极其重要的 Time 与 Window 详细解析(深度好文,建议收藏)

    前言 Flink 是流式的.实时的 计算引擎 上面一句话就有两个概念,一个是流式,一个是实时. 流式:就是数据源源不断的流进来,也就是数据没有边界,但是我们计算的时候必须在一个有边界的范围内进行,所以 ...

  7. Exception 异常处理

    https://github.com/jazzband/django-redis/blob/master/django_redis/exceptions.py django-redis/base.py ...

  8. Infrastructure as Code 行为驱动开发指南 https://www.ibm.com/developerworks/cn/devops/d-bbd-guide-iac/index.html

    Infrastructure as Code 行为驱动开发指南 https://www.ibm.com/developerworks/cn/devops/d-bbd-guide-iac/index.h ...

  9. 并发编程:Actors 模型和 CSP 模型

    https://mp.weixin.qq.com/s/emB99CtEVXS4p6tRjJ2xww 并发编程:Actors 模型和 CSP 模型 ImportNew 2017-04-27    

  10. libco协程原理简要分析

    此文简要分析一下libco协程的关键原理. 在分析前,先简单过一些协程的概念,以免有新手误读了此篇文章. 协程是用户态执行单元,它的创建,执行,上下文切换,挂起,销毁都是在用户态中完成,对linux系 ...