UVa 1658 (拆点法 最小费用流) Admiral

题意:

给出一个有向带权图,求从起点到终点的两条不相交路径使得权值和最小。

分析:

第一次听到“拆点法”这个名词。

把除起点和终点以外的点拆成两个点i和i',然后在这两点之间连一条容量为1,费用为0的边。这样就保证了每个点最多经过一次。

其他有向边的容量也是1

然后求从起点到终点的流量为2(这样就保证了是两条路径)的最小费用流。

 

  1 #include <bits/stdc++.h>

  2 

  3 using namespace std;

  4 

  5 const int maxn = 2000 + 10;

  6 const int INF = 1000000000;

  7 

  8 struct Edge

  9 {

 10     int from, to, cap, flow, cost;

 11     Edge(int u, int v, int c, int f, int w): from(u), to(v), cap(c), flow(f), cost(w) {}

 12 };

 13 

 14 struct MCMF

 15 {

 16     int n, m;

 17     vector<Edge> edges;

 18     vector<int> G[maxn];

 19     int inq[maxn]; //是否在队列中

 20     int d[maxn];    //Bellman-Ford

 21     int p[maxn];    //上一条弧

 22     int a[maxn];    //可改进量

 23 

 24     void Init(int n)

 25     {

 26         this->n = n;

 27         for(int i = 0; i < n; ++i) G[i].clear();

 28         edges.clear();

 29     }

 30 

 31     void AddEdge(int from, int to, int cap, int cost)

 32     {

 33         edges.push_back(Edge(from, to, cap, 0, cost));

 34         edges.push_back(Edge(to, from, 0, 0, -cost));

 35         m = edges.size();

 36         G[from].push_back(m-2);

 37         G[to].push_back(m-1);

 38     }

 39 

 40     bool BellmanFord(int s, int t, int flow_limit, int& flow, int& cost)

 41     {

 42         for(int i = 0; i < n; ++i) d[i] = INF;

 43         memset(inq, 0, sizeof(inq));

 44         d[s] = 0; inq[s] = 1; p[s] = 0; a[s] = INF;

 45 

 46         queue<int> Q;

 47         Q.push(s);

 48         while(!Q.empty())

 49         {

 50             int u = Q.front(); Q.pop();

 51             inq[u] = 0;

 52             for(int i = 0; i < G[u].size(); ++i)

 53             {

 54                 Edge& e = edges[G[u][i]];

 55                 if(e.cap > e.flow && d[e.to] > d[u] + e.cost)

 56                 {

 57                     d[e.to] = d[u] + e.cost;

 58                     p[e.to] = G[u][i];

 59                     a[e.to] = min(a[u], e.cap - e.flow);

 60                     if(!inq[e.to]) { Q.push(e.to); inq[e.to] = 1; }

 61                 }

 62             }

 63         }

 64         if(d[t] == INF) return false;

 65         if(flow + a[t] > flow_limit) a[t] = flow_limit - flow;

 66         flow += a[t];

 67         cost += d[t] * a[t];

 68         for(int u = t; u != s; u = edges[p[u]].from)

 69         {

 70             edges[p[u]].flow += a[t];

 71             edges[p[u]^1].flow -= a[t];

 72         }

 73         return true;

 74     }

 75 

 76     int MincostMaxflow(int s, int t, int flow_limit, int& cost)

 77     {

 78         int flow = 0; cost = 0;

 79         while(flow < flow_limit && BellmanFord(s, t, flow_limit, flow, cost));

 80         return flow;

 81     }

 82 }g;

 83 

 84 int main()

 85 {

 86     //freopen("in.txt", "r", stdin);

 87 

 88     int n, m;

 89     while(scanf("%d%d", &n, &m) == 2 && n)

 90     {

 91         g.Init(n*2-2);

 92         //2~n-1 i和i'的编号分别为1~n-2  n~2n-3

 93         for(int i = 2; i <= n-1; ++i) g.AddEdge(i-1, n-2+i, 1, 0);

 94         for(int i = 0; i < m; ++i)

 95         {   //连接a'->b

 96             int a, b, c;

 97             scanf("%d%d%d", &a, &b, &c);

 98             if(a != 1 && a != n) a += n-2; else a--;

 99             b--;

100             g.AddEdge(a, b, 1, c);

101         }

102         int cost;

103         g.MincostMaxflow(0, n-1, 2, cost);

104         printf("%d\n", cost);

105     }

106 

107     return 0;

108 }
代码君

 

你可能感兴趣的:(uva)