uva 1349(费用流)

题意:有若干城市组成一张有向图权值是花费,要你设计一个公交线路图是每个城市都经过一遍,然后要求总的花费最少。线路数量不限制只要覆盖到所有城市有且仅有一次就可以,输出最小费用。

思路:liurujia分在二分图里面的题目,第一眼看上去就像是费用流的题,想了一个多小时二分图做法没成功,还是用费用流a了。仔细观察我们可以发现设计出来的线路图必满足最大匹配数等于城市数(二分图两边都为城市)然后在这基础上费用最小。接下来就是建图套模版了。

补充:其实直接KM就能解决此题。。果断对算法理解还不到位。

代码如下:

  1 /**************************************************
  2  * Author     : xiaohao Z
  3  * Blog     : http://www.cnblogs.com/shu-xiaohao/
  4  * Last modified : 2014-02-26 00:33
  5  * Filename     : uva_1349.cpp
  6  * Description     : 
  7  * ************************************************/
  8 
  9 #include <iostream>
 10 #include <cstdio>
 11 #include <cstring>
 12 #include <cstdlib>
 13 #include <cmath>
 14 #include <algorithm>
 15 #include <queue>
 16 #include <stack>
 17 #include <vector>
 18 #include <set>
 19 #include <map>
 20 #define MP(a, b) make_pair(a, b)
 21 #define PB(a) push_back(a)
 22 
 23 using namespace std;
 24 typedef long long ll;
 25 typedef pair<int, int> pii;
 26 typedef pair<unsigned int,unsigned int> puu;
 27 typedef pair<int, double> pid;
 28 typedef pair<ll, int> pli;
 29 typedef pair<int, ll> pil;
 30 
 31 const int INF = 0x3f3f3f3f;
 32 const double eps = 1E-6;
 33 const int MAXN = 10000;
 34 const int MAXM = 100000;
 35 struct Edge{int to,next,cap,flow,cost;}edge[MAXM];
 36 int head[MAXN],tol;
 37 int pre[MAXN],dis[MAXN];
 38 bool vis[MAXN];
 39 int N;//节点总个数,节点编号从0~N-1
 40 
 41 void init(int n)
 42 {
 43     N = n;
 44     tol = 0;
 45     memset(head,-1,sizeof(head));
 46 }
 47 
 48 void addedge(int u,int v,int cap,int cost)
 49 {
 50     edge[tol].to = v;
 51     edge[tol].cap = cap;
 52     edge[tol].cost = cost;
 53     edge[tol].flow = 0;
 54     edge[tol].next = head[u];
 55     head[u] = tol++;
 56     edge[tol].to = u;
 57     edge[tol].cap = 0;
 58     edge[tol].cost = -cost;
 59     edge[tol].flow = 0;
 60     edge[tol].next = head[v];
 61     head[v] = tol++;
 62 }
 63 bool spfa(int s,int t)
 64 {
 65     queue<int>q;
 66     for(int i = 0; i < N; i++)
 67     {
 68         dis[i] = INF;
 69         vis[i] = false;
 70         pre[i] = -1;
 71     }
 72     dis[s] = 0;
 73     vis[s] = true;
 74     q.push(s);
 75     while(!q.empty())
 76     {
 77         int u = q.front();
 78         q.pop();
 79         vis[u] = false;
 80         for(int i = head[u]; i != -1; i = edge[i].next)
 81         {
 82             int v = edge[i].to;
 83             if(edge[i].cap > edge[i].flow &&
 84                     dis[v] > dis[u] + edge[i].cost )
 85             {
 86                 dis[v] = dis[u] + edge[i].cost;
 87                 pre[v] = i;
 88                 if(!vis[v])
 89                 {
 90                     vis[v] = true;
 91                     q.push(v);
 92                 }
 93             }
 94         }
 95     }
 96     if(pre[t] == -1)return false;
 97     else return true;
 98 }
 99 //返回的是最大流,cost存的是最小费用
100 int minCostMaxflow(int s,int t,int &cost)
101 {
102     int flow = 0;
103     cost = 0;
104     while(spfa(s,t))
105     {
106         int Min = INF;
107         for(int i = pre[t]; i != -1; i = pre[edge[i^1].to])
108         {
109             if(Min > edge[i].cap - edge[i].flow)
110                 Min = edge[i].cap - edge[i].flow;
111         }
112         for(int i = pre[t]; i != -1; i = pre[edge[i^1].to])
113         {
114             edge[i].flow += Min;
115             edge[i^1].flow -= Min;
116             cost += edge[i].cost * Min;
117         }
118         flow += Min;
119     }
120     return flow;
121 }
122 
123 int main()
124 {
125 //    freopen("in.txt", "r", stdin);
126 
127     int n, a, b;
128     while(scanf("%d", &n)!=EOF && n){
129         init(2*n+2);        
130         for(int i=0; i<n; i++){
131             while(scanf("%d", &a)!=EOF && a){
132                 scanf("%d", &b);
133                 addedge(i, a-1+n, 1, b);    
134             }
135         }
136         for(int i=0; i<n; i++){
137             addedge(2*n, i, 1, 0);
138             addedge(n+i, 2*n+1, 1, 0);
139         }
140         int cost, ans = minCostMaxflow(N-2, N-1, cost);
141         if(ans == n) printf("%d
", cost);
142         else printf("N
");
143     }
144     return 0;
145 }
View Code
奔跑吧!少年!趁着你还年轻
原文地址:https://www.cnblogs.com/shu-xiaohao/p/3568186.html