题目传送门

  传送门

题目大意

  给定一个费用流,每条边有一个初始流量$c_i$和单位流量费用$d_i$,增加一条边的1单位的流量需要花费$b_i$的代价而减少一条边的1单位的流量需要花费$a_i$的代价。要求最小化总费用减少量和调整次数的比值(至少调整一次)。

  根据基本套路,二分答案,移项,可以得到每条边的贡献。

  设第$i$条边的流量变化量为$m_i$,每次变化花费的平均费用为$w_i$。那么有

$\sum c_id_i - \sum (c_i + m_i)d_i + |m_i|(w_i + mid) > 0$

$\sum m_id_i+ |m_i|(w_i + mid) < 0$

  那么二分答案后等于判断是否存在一个增广环的费用和为负。(请手动参见式子脑补边权)。

  然后可以写个spfa。

Code

  1 /**
  2  * bzoj
  3  * Problem#3597
  4  * Accepted
  5  * Time: 464ms
  6  * Memory: 1720k
  7  */
  8 #include <iostream>
  9 #include <cstdlib>
 10 #include <cstdio>
 11 #include <vector>
 12 #include <queue>
 13 using namespace std;
 14 typedef bool boolean;
 15 
 16 template <typename T>
 17 void pfill(T* pst, const T* ped, T val) {
 18     for ( ; pst != ped; *(pst++) = val);
 19 }
 20 
 21 typedef class Edge {
 22     public:
 23         int ed, nx;
 24         double w;
 25 
 26         Edge(int ed, int nx, double w) : ed(ed), nx(nx), w(w) {    }
 27 } Edge;
 28 
 29 typedef class MapManager {
 30     public:
 31         int* h;
 32         vector<Edge> es;
 33 
 34         MapManager() {    }
 35         MapManager(int n) {
 36             h = new int[(n + 1)];
 37             pfill(h, h + n + 1, -1);
 38         }
 39         ~MapManager() {
 40             delete[] h;
 41             es.clear();
 42         }
 43 
 44         void addEdge(int u, int v, double w) {
 45             es.push_back(Edge(v, h[u], w));
 46             h[u] = (signed) es.size() - 1;
 47         }
 48 
 49         Edge& operator [] (int p) {
 50             return es[p];
 51         }
 52 } MapManager;
 53 
 54 const double dinf = 1e10;
 55 const double eps = 1e-4;
 56 
 57 typedef class Graph {
 58     public:
 59         int n, s;
 60         MapManager g;
 61         
 62         int *cnt;
 63         double *f;
 64         boolean *vis;
 65 
 66         Graph(int n, int s) : n(n), s(s), g(n) {
 67             cnt = new int[(n + 1)];
 68             f = new double[(n + 1)];
 69             vis = new boolean[(n + 1)];
 70             pfill(vis, vis + n + 1, false);
 71         }
 72 
 73         boolean neg_circle() {
 74             static queue<int> que;
 75             pfill(f, f + n + 1, dinf);
 76             pfill(cnt, cnt + n + 1, 0);
 77             f[s] = 0, cnt[s]++;
 78             que.push(s);
 79             while (!que.empty()) {
 80                 int e = que.front();
 81                 que.pop();
 82                 vis[e] = false;
 83                 for (int i = g.h[e], eu; ~i; i = g[i].nx) {    
 84                     eu = g[i].ed;
 85                     double w = f[e] + g[i].w;
 86                     if (w < f[eu]) {
 87                         f[eu] = w, cnt[eu]++;
 88                         if (cnt[eu] > n)
 89                             return true;
 90                         if (!vis[eu]) {
 91                             que.push(eu);
 92                             vis[eu] = true; 
 93                         }
 94                     }
 95                 }
 96             }
 97             return false;
 98         }
 99 } Graph;
100 
101 int n, m;
102 int *u, *v, *a, *b, *c, *d;
103 double init_ans = 0.0;
104 
105 inline void init() {
106     scanf("%d%d", &n, &m);
107     u = new int[(m + 1)];
108     v = new int[(m + 1)];
109     a = new int[(m + 1)];
110     b = new int[(m + 1)];
111     c = new int[(m + 1)];
112     d = new int[(m + 1)];
113     for (int i = 1; i <= m; i++) {
114         scanf("%d%d%d%d%d%d", u + i, v + i, a + i, b + i, c + i, d + i);
115         init_ans += c[i] * d[i];
116     }
117 }
118 
119 boolean check(double mid) {
120     Graph graph(n + 2, n + 1);
121     MapManager& g = graph.g;
122     
123     for (int i = 1; i <= m; i++) {
124         if (u[i] == n + 1) {
125             g.addEdge(u[i], v[i], 0);
126         } else if (c[i]) {
127             g.addEdge(u[i], v[i], d[i] + b[i] + mid);
128             g.addEdge(v[i], u[i], -d[i] + a[i] + mid);
129         } else {
130             g.addEdge(u[i], v[i], d[i] + b[i] + mid);
131         }
132     }
133 
134     return graph.neg_circle();
135 }
136 
137 inline void solve() {
138     double l = 0, r = init_ans, mid;
139     for (int t = 0; t < 128 && l < r - eps; t++) {
140         mid = (l + r) / 2;
141         if (check(mid))
142             l = mid;
143         else
144             r = mid;
145     }
146     printf("%.2lf\n", l);
147 }
148 
149 int main() {
150     init();
151     solve();
152     return 0;
153 }
spfa

相关文章: