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

http://acm.hdu.edu.cn/showproblem.php?pid=3488

题意:

给出n个点和m条边,每条边有距离,把这n个点分成1个或多个环,且每个点只能在一个环中,保证有解。

 

思路:

把一个点分成两部分,1~n和n+i~2*n。

连边的情况是这样的,(src,i,1,0),(i+n,dst,1,0)。

如果两个点之间相同,则(i,j+n,1,d)。

其实这道题目就是选n条边,如何使得权值之和最小。

具体请参考这http://blog.csdn.net/u013480600/article/details/39185013

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cmath>
  4 #include<cstring>
  5 #include<queue>
  6 using namespace std;
  7 typedef long long LL;
  8 
  9 const int maxn=400+5;
 10 const int INF=0x3f3f3f3f;
 11 
 12 struct Edge
 13 {
 14     int from, to, cap, flow, cost;
 15     Edge(int u, int v, int c, int f, int w) :from(u), to(v), cap(c), flow(f), cost(w) {}
 16 };
 17 
 18 struct MCMF
 19 {
 20     int n, m;
 21     vector<Edge> edges;
 22     vector<int> G[maxn];
 23     int inq[maxn];
 24     int d[maxn];
 25     int p[maxn];
 26     int a[maxn];
 27 
 28     void init(int n)
 29     {
 30         this->n = n;
 31         for (int i = 0; i<n; i++) G[i].clear();
 32         edges.clear();
 33     }
 34 
 35     void AddEdge(int from, int to, int cap, int cost)
 36     {
 37         edges.push_back(Edge(from, to, cap, 0, cost));
 38         edges.push_back(Edge(to, from, 0, 0, -cost));
 39         m = edges.size();
 40         G[from].push_back(m - 2);
 41         G[to].push_back(m - 1);
 42     }
 43 
 44     bool BellmanFord(int s, int t, int &flow, LL & cost)
 45     {
 46         for (int i = 0; i<n; i++) d[i] = INF;
 47         memset(inq, 0, sizeof(inq));
 48         d[s] = 0; inq[s] = 1; p[s] = 0; a[s] = INF;
 49 
 50         queue<int> Q;
 51         Q.push(s);
 52         while (!Q.empty()){
 53             int u = Q.front(); Q.pop();
 54             inq[u] = 0;
 55             for (int i = 0; i<G[u].size(); i++){
 56                 Edge& e = edges[G[u][i]];
 57                 if (e.cap>e.flow && d[e.to]>d[u] + e.cost){
 58                     d[e.to] = d[u] + e.cost;
 59                     p[e.to] = G[u][i];
 60                     a[e.to] = min(a[u], e.cap - e.flow);
 61                     if (!inq[e.to]) { Q.push(e.to); inq[e.to] = 1; }
 62                 }
 63             }
 64         }
 65         if (d[t] == INF) return false;
 66         flow += a[t];
 67         cost += (LL)d[t] * (LL)a[t];
 68         for (int u = t; u != s; u = edges[p[u]].from){
 69             edges[p[u]].flow += a[t];
 70             edges[p[u] ^ 1].flow -= a[t];
 71 
 72         }
 73         return true;
 74     }
 75 
 76     void MincostMaxdflow(int s, int t, LL & cost)
 77     {
 78         int flow = 0; cost = 0;
 79         while (BellmanFord(s, t, flow, cost) );
 80         //return flow;
 81     }
 82 }t;
 83 
 84 int n,m;
 85 
 86 int main()
 87 {
 88     //freopen("D:\\input.txt", "r", stdin);
 89     int T;
 90     scanf("%d",&T);
 91     int u,v,d;
 92     while(T--)
 93     {
 94         scanf("%d%d",&n,&m);
 95         int src=0,dst=2*n+1;
 96         t.init(dst+1);
 97         for(int i=1;i<=n;i++)
 98         {
 99             t.AddEdge(src,i,1,0);
100             t.AddEdge(i+n,dst,1,0);
101         }
102         for(int i=0;i<m;i++)
103         {
104             scanf("%d%d%d",&u,&v,&d);
105             t.AddEdge(u,v+n,1,d);
106         }
107         long long cost;
108         t.MincostMaxdflow(src,dst,cost);
109         printf("%d\n",cost);
110     }
111     return 0;
112 }

 

转载于:https://www.cnblogs.com/zyb993963526/p/6697054.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值