题意:树上每个节点上有若干苹果,边上带权,问你最小费用使得书上的苹果方差最小。
思路:上下费用流问题,参考http://blog.csdn.net/qq564690377/article/details/8870587
代码如下:
1 /**************************************************
2 * Author : xiaohao Z
3 * Blog : http://www.cnblogs.com/shu-xiaohao/
4 * Last modified : 2014-05-13 12:02
5 * Filename : zoj_3231_2.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 int a, b, n, vex[101], val, sum;
127 while(scanf("%d", &n)!=EOF){
128 sum = 0;
129 for(int i=1; i<=n; i++){
130 scanf("%d", &vex[i]);
131 sum += vex[i];
132 }
133 init(n+3);
134 for(int i=1; i<n; i++){
135 scanf("%d%d%d", &a, &b, &val);
136 a++, b++;
137 addedge(a, b, INF, val);
138 addedge(b, a, INF, val);
139 }
140 for(int i=1; i<=n; i++){
141 addedge(0, i, vex[i], 0);
142 addedge(i, n+1, sum/n, 0);
143 addedge(i, n+2, 1, 0);
144 }
145 addedge(n+2, n+1, sum%n, 0);
146 int ans;
147 minCostMaxflow(0, n+1, ans);
148 printf("%d\n", ans);
149 }
150 return 0;
151 }
zoj 3231(上下界费用流),布布扣,bubuko.com
时间: 2024-10-21 10:50:12