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, int cap = 0, int flow = 0, int cost = 0, int nxt = 0) :
 11         u(u), v(v), cap(cap), flow(flow), cost(cost), nxt(nxt) {}
 12 }e[maxe << 1];
 13
 14 int head[maxv];
 15 int cnt;
 16 void init(){
 17     cnt = 0;
 18     memset(head, -1, sizeof head);
 19 }
 20
 21 void add(int u, int v, int cap, int cost){
 22     e[cnt] = Edge(u, v, cap, 0, cost, head[u]);
 23     head[u] = cnt++;
 24     e[cnt] = Edge(v, u, 0, 0, -cost, head[v]);
 25     head[v] = cnt++;
 26 }
 27
 28 int N;
 29 int d[maxv], p[maxv], a[maxv], inq[maxv];
 30 bool BellmanFord(int s, int t, int &flow, int &cost){
 31     for(int i = 0; i < N; i++) d[i] = inf;
 32     memset(inq, 0, sizeof inq);
 33     d[s] = 0, a[s] = inf, p[s] = 0, inq[s] = 1;
 34     queue<int> q;
 35     q.push(s);
 36     while(!q.empty()){
 37         int u = q.front();
 38         q.pop();
 39         inq[u] = 0;
 40         for(int i = head[u]; ~i; i = e[i].nxt){
 41             Edge &tp = e[i];
 42             if(tp.cap > tp.flow && d[tp.v] > d[u] + tp.cost){
 43                 d[tp.v] = d[u] + tp.cost;
 44                 p[tp.v] = i;
 45                 a[tp.v] = min(a[u], tp.cap - tp.flow);
 46                 if(!inq[tp.v]){
 47                     q.push(tp.v);
 48                     inq[tp.v] = 1;
 49                 }
 50             }
 51         }
 52     }
 53     if(d[t] == inf) return false;
 54     flow += a[t];
 55     cost += a[t] * d[t];
 56     int u = t;
 57     while(u != s){
 58         e[p[u]].flow += a[t];
 59         e[p[u] ^ 1].flow -= a[t];
 60         u = e[p[u]].u;
 61     }
 62     return true;
 63 }
 64
 65
 66 int MCMF(int s, int t){
 67     int flow = 0, cost = 0;
 68     while(BellmanFord(s, t, flow, cost));
 69     return cost;
 70 }
 71
 72 int gra[maxv<<1][maxv<<1];
 73 int main(){
 74     int t;
 75     scanf("%d", &t);
 76     while(t--){
 77         memset(gra, inf, sizeof(gra));
 78         init();
 79         int n, m;
 80         scanf("%d %d", &n, &m);
 81         int u, v, w;
 82         for(int i = 0; i < m; i++){
 83             scanf("%d %d %d", &u, &v, &w);
 84             gra[u * 2 + 1][v * 2] = min(gra[u * 2 + 1][v * 2], w);
 85         }
 86         for(int i = 2; i <= n * 2 + 1; i++){
 87             for(int j = 2; j <= n * 2 + 1; j++){
 88                 if(gra[i][j] != inf) add(i, j, 1, gra[i][j]);
 89             }
 90         }
 91         int S = 0, T = 1;
 92         N = 2 * n + 2;
 93         for(int i = 1; i <= n; i++){
 94             add(S, i * 2 + 1, 1, 0);
 95             add(i * 2, T, 1, 0);
 96         }
 97         printf("%d\n", MCMF(S, T));
 98     }
 99     return 0;
100 }

也可以用KM

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int maxv=210;
 4 const int inf=0x3f3f3f3f;
 5
 6 int vb[maxv],vg[maxv],eb[maxv],eg[maxv];
 7 int c[maxv][maxv];
 8 int slack[maxv];
 9 int mc[maxv];
10 #define CLR(m,a) memset(m,a,sizeof(m))
11 int n,m;
12 int dfs(int x)
13 {
14     vg[x]=1;
15     for(int i=0;i<n;i++)
16     {
17         if(vb[i]) continue;
18         int gap=eg[x]+eb[i]-c[x][i];
19         if(gap==0)
20         {
21             vb[i]=1;
22             if(mc[i]==-1||dfs(mc[i]))
23             {
24                 mc[i]=x;
25                 return 1;
26             }
27         }
28         else slack[i]=min(slack[i],gap);
29     }
30     return 0;
31 }
32 int KM()
33 {
34     CLR(mc,-1);
35     CLR(eb,0);
36     for(int i=0;i<n;i++)
37     {
38         eg[i]=c[i][0];
39         for(int j=1;j<n;j++)
40             eg[i]=max(eg[i],c[i][j]);
41     }
42     for(int i=0;i<n;i++)
43     {
44         CLR(slack,inf);
45         while(1)
46         {
47             CLR(vb,0);
48             CLR(vg,0);
49             if(dfs(i)) break;
50             int d=inf;
51             for(int i=0;i<n;i++) if(!vb[i]) d=min(d,slack[i]);
52             for(int i=0;i<n;i++)
53             {
54                 if(vg[i]) eg[i]-=d;
55                 if(vb[i]) eb[i]+=d;
56                 else slack[i]-=d;
57             }
58         }
59     }
60     int ans=0;
61     for(int i=0;i<n;i++)
62     {
63         if(mc[i]==-1) return -1;
64         if(c[mc[i]][i]==-inf) return -1;
65         ans+=c[mc[i]][i];
66     }
67     return -ans;
68 }
69 int main()
70 {
71     int t;
72     scanf("%d",&t);
73     while(t--)
74     {
75         scanf("%d%d",&n,&m);
76         int u,v,w;
77        for(int i=0;i<n;i++)
78         for(int j=0;j<n;j++) c[i][j]=-inf;
79         for(int i=0;i<m;i++)
80         {
81             scanf("%d%d%d",&u,&v,&w);
82             u--;v--;
83             c[u][v]=max(-w,c[u][v]);
84         }
85         printf("%d\n",KM());
86     }
87 }

不同的是建图的时候的区别,费用流要拆点,而KM不用,因为KM左右两边的点已经视为不同了。

这个题还要注意有重边,费用流盲目建图会TLE。

原文地址:https://www.cnblogs.com/yijiull/p/8319875.html

时间: 2024-10-09 14:16:54

Tour HDU - 3488的相关文章

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

Q - Tour - hdu 3488(最小匹配值)

题意:一个王国有N个城市,M条路,都是有向的,现在可以去旅游,不过走的路只能是环(至少也需要有两个城市),他们保证这些城市之间的路径都是有环构成的,现在至少需要走多少路. 分析:因为是有向图所以,而且走的是环所以每个城市都会进入一次并且出去一次,构成二分图,并且是完备匹配(完备匹配后肯定都是环了),现在只需要求出来这些匹配的最小值就行,可以把路径的值变为负数,然后求最大匹配值,最后的结果在变成相反数即可,注意路径可能有多条,输入的时候注意取最小的那个 **********************

Hdu 3488 Tour (KM 有向环覆盖)

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

POJ 2135 Farm Tour &amp;&amp; HDU 2686 Matrix &amp;&amp; HDU 3376 Matrix Again 费用流求来回最短路

累了就要写题解,最近总是被虐到没脾气. 来回最短路问题貌似也可以用DP来搞,不过拿费用流还是很方便的. 可以转化成求满流为2 的最小花费.一般做法为拆点,对于 i 拆为2*i 和 2*i+1,然后连一条流量为1(花费根据题意来定) 的边来控制每个点只能通过一次. 额外添加source和sink来控制满流为2. 代码都雷同,以HDU3376为例. #include <algorithm> #include <iostream> #include <cstring> #in

hdu 1853 Cyclic Tour &amp;&amp; hdu 3435 A new Graph Game(简单KM算法)

Cyclic Tour Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/65535 K (Java/Others) Total Submission(s): 1478    Accepted Submission(s): 750 Problem Description There are N cities in our country, and M one-way roads connecting them. Now L

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【多个环的并】

大意:告诉你一些国家和一些单项路,每条路连接两个国家,告诉你之间的距离,现在要使每个国家都在一个环中 求最小距离 分析:这是做过的第二个多个环的并的问题 每个点的入读和出度都为1 把n个点拆点 由于二分图最优匹配的性质可知每个点都会出现在匹配中 相当于每个点出现一次 左边为出度点  有边为入读点 值得注意的是两个国家可能会有多条路 要选取最短的 ----想起东北赛死在这上边了   ----全都是泪啊 代码: 1 #include <iostream> 2 #include <cstdio

HDU 3488 Tour

有向环最小权值覆盖问题 http://blog.csdn.net/u013480600/article/details/39159407 #include<cstdio> #include<cstring> #include<cmath> #include<vector> #include<queue> #include<algorithm> using namespace std; //设置节点数量 const int maxn=4

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

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