bzoj2055 80人环游世界
传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2055
【题解】
跟上一题(支线剧情)很像,与上题不同是这题看作求“最大流”(我们限制过流量了),上一题是求“可行流”无源汇的做法。
我们考虑先建出带有上下界的网络流:
S1->S2 [m,m] cost = 0
out(i)->in(j) [0, inf] cost = p[i][j]
in(i)->out(i) [vi, vi] cost = 0;
out(i)->T [0, inf] cost = 0
注意p[i][j]=-1不要建边
那么这样过后,直接按照通常转成非下界限制的费用流做就行了
因为这题有源汇,所以不需要提前算答案
# include <queue> # include <stdio.h> # include <string.h> # include <iostream> # include <algorithm> // # include <bits/stdc++.h> using namespace std; typedef long long ll; typedef long double ld; typedef unsigned long long ull; const int M = 5e5 + 10, N = 210; const int mod = 1e9+7; # define RG register # define ST static int n, m, S, T; int p[N][N], V[N], d[N]; int head[M], nxt[M], to[M], flow[M], w[M], tot=1; inline void add(int u, int v, int fl, int _w) { ++tot; nxt[tot] = head[u]; head[u] = tot; to[tot] = v; flow[tot] = fl; w[tot] = _w; } inline void adde(int u, int v, int fl, int _w) { add(u, v, fl, _w); add(v, u, 0, -_w); } namespace MCF { queue<int> q; int dis[M], pre[M]; bool vis[M]; inline bool spfa() { while(!q.empty()) q.pop(); for (int i=1; i<=n+n+5; ++i) vis[i] = 0, dis[i] = 1e9, pre[i] = 0; q.push(S); vis[S] = 1; dis[S] = 0; while(!q.empty()) { int top = q.front(); q.pop(); vis[top] = 0; for (int i=head[top]; i; i=nxt[i]) { if(flow[i] && dis[to[i]] > dis[top] + w[i]) { dis[to[i]] = dis[top] + w[i]; pre[to[i]] = i; if(!vis[to[i]]) { vis[to[i]] = 1; q.push(to[i]); } } } } return dis[T] != 1e9; } inline int mcf() { int fl = 1e9, ans = 0; for (int i=pre[T]; i; i=pre[to[i^1]]) fl = min(fl, flow[i]); for (int i=pre[T]; i; i=pre[to[i^1]]) { flow[i] -= fl; flow[i^1] += fl; ans += fl * w[i]; } return ans; } inline int main() { int ret = 0; while(spfa()) ret += mcf(); return ret; } } inline void ADD(int u, int v, int fll, int flr, int _w) { adde(u, v, flr-fll, _w); d[v] += fll; d[u] -= fll; } int main() { cin >> n >> m; for (int i=1; i<=n; ++i) scanf("%d", &V[i]); for (int i=1; i<=n; ++i) for (int j=i+1; j<=n; ++j) scanf("%d", &p[i][j]); int S1 = n+n+1, S2 = n+n+2, T0 = n+n+3; for (int i=1; i<=n; ++i) ADD(i, i+n, V[i], V[i], 0); for (int i=1; i<=n; ++i) for (int j=i+1; j<=n; ++j) if(p[i][j] != -1) ADD(i+n, j, 0, 1e9, p[i][j]); ADD(S1, S2, m, m, 0); for (int i=1; i<=n; ++i) ADD(S2, i, 0, 1e9, 0); for (int i=1; i<=n; ++i) ADD(i+n, T0, 0, 1e9, 0); S = n+n+4, T = n+n+5; for (int i=1; i<=n+n+3; ++i) { if(d[i] > 0) adde(S, i, d[i], 0); if(d[i] < 0) adde(i, T, -d[i], 0); } cout << MCF::main() << endl; return 0; }