hdu--3488--km<先人太聪明了>

发明这个算法的人 太聪明了 想到了顶标这个概念 -.-

虽然 图论就是个建图过程 然后就是模板的使用 但是 一定要理解这个算法 模板 真的....

我给2个我看资料的链接..传送1

传送2

这题的话 有一点特殊 就是需要求 相反数 因为问的是 最小值...还有 这题有重边的存在 开始WA在这里-.-

  1 #include <iostream>
  2 #include <cstring>
  3 #include <algorithm>
  4 using namespace std;
  5
  6 int n;
  7 const int size = 220;
  8 const int inf = 0x3f3f3f3f;
  9 int mp[size][size];
 10 int lx[size] , ly[size];
 11 int linker[size];
 12 bool visx[size] , visy[size];
 13 int slack[size];
 14
 15 bool dfs( int x )
 16 {
 17     int temp;
 18     visx[x] = true;
 19     for( int y = 1 ; y<=n ; y++ )
 20     {
 21         if( !visy[y] )
 22         {
 23             temp = lx[x] + ly[y] - mp[x][y];
 24             if( temp==0 )
 25             {
 26                 visy[y] = true;
 27                 if( linker[y] == -1||dfs(linker[y]) )
 28                 {
 29                     linker[y] = x;
 30                     return true;
 31                 }
 32             }
 33             else if( slack[y] > temp )
 34             {
 35                 slack[y] = temp;
 36             }
 37         }
 38     }
 39     return false;
 40 }
 41
 42 void km( )
 43 {
 44     int temp , ans = 0;
 45     memset( ly , 0 , sizeof(ly) );//开始Y集合中顶标初始化为0
 46     memset( linker , -1 , sizeof(linker) );//Y集合中某元素的边的另一端点
 47     for( int i = 1 ; i<=n ; i++ )
 48     {
 49         lx[i] = -inf;
 50         for( int j = 1 ; j<=n ; j++ )
 51         {
 52             if( mp[i][j]>lx[i] )
 53             {
 54                 lx[i] = mp[i][j];
 55             }
 56         }
 57     }
 58     for( int x = 1 ; x<=n ; x++ )
 59     {
 60         for( int i = 1 ; i<=n ; i++ )
 61         {
 62             slack[i] = inf;
 63         }
 64         while( true )
 65         {
 66             memset( visx , false , sizeof(visx) );
 67             memset( visy , false , sizeof(visy) );
 68             if( dfs(x) )
 69                 break;
 70             temp = inf;
 71             for( int y = 1 ; y<=n ; y++ )
 72             {
 73                 if( !visy[y] && temp>slack[y] )
 74                     temp = slack[y];
 75             }
 76             for( int x = 1 ; x<=n ; x++ )
 77             {
 78                 if( visx[x] )
 79                     lx[x] -= temp;
 80             }
 81             for( int y = 1 ; y<=n ; y++ )
 82             {
 83                 if( visy[y] )
 84                     ly[y] += temp;
 85                 else
 86                     slack[y] -= temp;
 87             }
 88         }
 89     }
 90     for( int i = 1 ; i<=n ; i++ )
 91     {
 92         ans += mp[ linker[i] ][i];
 93         cout << linker[i] << " " << i << endl;
 94     }
 95     cout << -ans << endl;
 96 }
 97
 98 int main()
 99 {
100     int t , m , st , end , dist;
101     while( cin>>t )
102     {
103         while( t-- )
104         {
105             memset( mp , -inf , sizeof(mp) );
106             cin >> n >> m;
107             while( m-- )
108             {
109                 cin >> st >> end >> dist;
110                 mp[st][end] = mp[st][end] < -dist ? -dist : mp[st][end];
111             }
112             km();
113         }
114     }
115     return 0;
116 }

这里 我想最重要的概念就是--交错树了--我还没有对KM理解地很好 不做自己想法的阐述了

today:

  如果你是鱼,不要迷恋天空;如果你是鸟,不要痴情海洋。——汪国真

hdu--3488--km<先人太聪明了>,布布扣,bubuko.com

时间: 2024-11-12 10:02:13

hdu--3488--km<先人太聪明了>的相关文章

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

Tour Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)Total Submission(s): 2925    Accepted Submission(s): 1407 Problem Description In the kingdom of Henryy, there are N (2 <= N <= 200) cities, with M (M <= 30000

Hdu 3488 Tour (KM 有向环覆盖)

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

HDU 3435 KM A new Graph Game

和HDU 3488一样的,只不过要判断一下是否有解. 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <vector> 6 using namespace std; 7 8 const int maxn = 1000 + 10; 9 const int INF = 0x3f3f3f3f; 10 11 i

Tour HDU - 3488

Tour HDU - 3488 可以用费用流做 1 #include <bits/stdc++.h> 2 using namespace std; 3 const int inf = 0x3f3f3f3f; 4 const int maxv = 410; 5 const int maxe = maxv * maxv; 6 7 struct Edge{ 8 int u, v, cap, flow, cost; 9 int nxt; 10 Edge(int u = 0, int v = 0, in

hdu 4862 KM算法 最小K路径覆盖的模型

http://acm.hdu.edu.cn/showproblem.php?pid=4862 选t<=k次,t条路要经过所有的点一次并且仅仅一次, 建图是问题: 我自己最初就把n*m 个点分别放入X集合以及Y集合,再求最优匹配,然后连样例都过不了,而且其实当时解释不了什么情况下不能得到结果,因为k此这个条件相当于没用上... 建图方法: 1.X集合和Y集合都放入n*m+k个点,X中前n*m个点和Y中前n*m个点之间,如果格子里的值相等,权就是(收益-耗费),不等就是(-耗费),因为要的是最大收益

hdu1853/ hdu 3488 有向图,取k个圈覆盖所有点一次//费用流

哎╮(╯▽╰)╭,这是费用流基础题型,拆点,建二分图,跑最小费用最大流即可.若最大流为n,则说明是最大匹配为n,所有点都参与,每个点的入度和出度又是1,所以就是环. 弱菜还需努力! #include<cstdio> #include<iostream> #include<queue> #include<cstring> using namespace std; const int inf=0x3f3f3f3f; int nume=0;int e[50000]

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

<题目链接> 题目大意:给出n个点m条单向边边以及经过每条边的费用,让你求出走过一个哈密顿环(除起点外,每个点只能走一次)的最小费用.题目保证至少存在一个环满足条件. 解题分析: 因为要求包含所有点一次的环,我们不难发现,这个环中的每个点的出度和入度均为1,所以我们不妨将每个点进行拆点,将所有点的出度和入度分为两部分.因为该环需要包括所有的点,并且题目需要求该环的最小权值,相当于该带权二分图的每个点都需要被覆盖到,由于本题就转化为求该二分图的最优完美匹配问题.二分图的最优匹配问题求解,我们会想

HDU 2255 &amp; KM模板

题意: 一张完备二分图求最优完备匹配. SOL: 这题就不讲什么sol了...毕竟是裸的KM,不会的话可以看老人家的大白鼠,一些问题看代码注释.讲讲经历(悲惨的经历) 刚打完,自信地交上去发现MLE...一脸大雾...然后才开始看数据..300^4啊...看起来会炸的样子,那么加个优化好了.还是MLE!真是奇了怪了.然后就在提交里看别人是不是用的邻接表——清一色邻接矩阵!再想想KM搞的都是完备图啊邻接表和邻接矩阵用起来没什么不同.那么没问题啊?然后交来交去交了8次...直到zyh大神——虽然他从

HDU 2853 (KM最大匹配)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2853 题目大意:二分图匹配费用流.①最大匹配②最小原配变动 解题思路: 如果去掉第二个要求,那么就是裸KM. 然而加上第二个要求,那么就需要一种新的建图方式. 建图 对于输入矩阵,每一条边,cost扩大K倍($K=n+1$) 对于原配,每一条边cost在扩大K倍基础上+1 KM 统计cost时,直接把cost整除K,然后累加. 并且Hash一下原配边的变动情况. 扩大K倍的作用 准确来说,K倍是为了