[SDOI2013]費用流
阿新 • • 發佈:2018-01-06
fill space pre clu etc while getchar() pty printf
然而這是一道網絡流。。。
如果滿足Bob,使總費用最大:
設最大流的每條邊流量(不是容量)為w[i],分配到每條邊的費用為p[i],最大流量為wmax,p[i]的和為P
那麽顯然w[i] * p[i]的和小於等於wmax * P
證明:
\[wmax * P = \sum wmax * p[i].....................(1)\]
\[(1) - \sum w[i]*p[i] = \sum (wmax - w[i]) * p[i] \ge 0\]
證畢
那麽如果滿足Alice,使總費用最小
就只要使得最大流中最大的流量的邊的流量最小
於是二分這個最小流量,把所有邊的容量對它取min後跑一遍容量為分數的最大流,與原本的最大流比較即可
# include <bits/stdc++.h> # define IL inline # define RG register # define Fill(a, b) memset(a, b, sizeof(a)) # define Copy(a, b) memcpy(a, b, sizeof(a)) using namespace std; typedef long long ll; const int _(110), __(2010), INF(2147483647); IL ll Read(){ RG char c = getchar(); RG ll x = 0, z = 1; for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1; for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48); return x * z; } int n, m, fst[_], nxt[__], to[__], cnt, A[__], B[__], p, S, T, lev[_], cur[_]; double C[__], w[__], max_flow, ans; queue <int> Q; IL void Add(RG int u, RG int v, RG double f){ w[cnt] = f; to[cnt] = v; nxt[cnt] = fst[u]; fst[u] = cnt++; w[cnt] = 0; to[cnt] = u; nxt[cnt] = fst[v]; fst[v] = cnt++; } IL double Dfs(RG int u, RG double maxf){ if(u == T) return maxf; RG double ret = 0; for(RG int &e = cur[u]; e != -1; e = nxt[e]){ if(lev[to[e]] != lev[u] + 1 || !w[e]) continue; RG double f = Dfs(to[e], min(w[e], maxf - ret)); ret += f; w[e ^ 1] += f; w[e] -= f; if(ret == maxf) break; } if(!ret) lev[u] = 0; return ret; } IL bool Bfs(){ Fill(lev, 0); lev[S] = 1; Q.push(S); while(!Q.empty()){ RG int u = Q.front(); Q.pop(); for(RG int e = fst[u]; e != -1; e = nxt[e]){ if(lev[to[e]] || !w[e]) continue; lev[to[e]] = lev[u] + 1; Q.push(to[e]); } } return lev[T]; } IL double Check(RG double x){ Fill(fst, -1); cnt = 0; for(RG int i = 1; i <= m; i++) Add(A[i], B[i], min(C[i], x)); for(max_flow = 0; Bfs(); ) Copy(cur, fst), max_flow += Dfs(S, INF); return max_flow; } int main(RG int argc, RG char* argv[]){ n = Read(); m = Read(); p = Read(); S = 1; T = n; for(RG int i = 1; i <= m; i++) A[i] = Read(), B[i] = Read(), C[i] = Read(); ans = Check(INF); RG double l = 0, r = 1000000; while(r - l >= 1e-6){ RG double mid = (l + r) / 2; if(ans == Check(mid)) r = mid; else l = mid; } printf("%.0lf\n%.4lf\n", ans, l * p); return 0; }
[SDOI2013]費用流