[bzoj2055] 80人環遊世界
Description
想必大家都看過成龍大哥的《 \(80\) 天環遊世界》,裏面的緊張刺激的打鬥場面一定給你留下了深刻的印象。現在就有這麽
一個 \(80\) 人的團夥,也想來一次環遊世界。
他們打算兵分多路,遊遍每一個國家。
因為他們主要分布在東方,所以他們只朝西方進軍。設從東方到西方的每一個國家的編號依次為 \(1\cdots N\) 。假若第i個人的遊歷路線為 \(P_1,P_2\cdots P_k(0\le k\le N)\),則 \(P_1<P_2<\cdots <P_k\) 。
眾所周知,中國相當美麗,這樣在環遊世界時就有很多人經過中國。我們用一個正整數 \(V_i\)
為了節省時間,他們打算通過坐飛機來完成環遊世界的任務。同時為了省錢,他們希望總的機票費最小。
明天就要出發了,可是有些人臨陣脫逃,最終只剩下了 \(M\) 個人去環遊世界。他們想知道最少的總費用,你能告訴他們嗎?
Input
第一行兩個正整數 \(N,M\) 。
第二行有 \(N\) 個不大於 \(M\) 正整數,分別表示 \(V_1,V_2\cdots V_N\)。
接下來有 \(N-1\) 行。第 \(i\) 行有 \(N -i\) 個整數,該行的第 \(j\) 個數表示從第 \(i\)
Output
在第一行輸出最少的總費用。
Sample Input
6 3
2 1 3 1 2 1
2 6 8 5 0
8 2 4 1
6 1 0
4 -1
4
Sample Output
27
HINT
\(1\le N \le 100,1\le M \le 79\)
Solution
這大概就是題面欽定數據範圍吧...
這是一道上下界費用流。
將國家 \(x\) 拆成入點 \(x_1\) ,出點 \(x_2\) ,同時建源點 \(S\) ,匯點 \(T\) ,第二源點 \(SS\) 。
首先 \[<S, SS>:capacity=m,cost=0\]
對於國家 \(x\) \[<SS,x_1>:capacity=INF,cost = 0\] \[<x_2,T>:capacity=INF,cost=0\] \[<x_1,x_2>:capacity=[V, V],cost=0\]
如果 \(x\) 到 \(y\) 有航線,則 \[<x_2,y_1>:capacity=INF,cost=W\]
然後跑一個上下界費用流即可。具體做法是先把每條邊的 \(lw\) 乘上 \(cost\) 加到答案裏(當然本題不需要),再跑一個普通的費用流。
#include<bits/stdc++.h>
using namespace std;
#define N 1001
#define INF 2000000000
#define rep(i, a, b) for (int i = a; i <= b; i++)
#define ll long long
inline int read() {
int x = 0, flag = 1; char ch = getchar(); while (!isdigit(ch)) { if (!(ch ^ '-')) flag = -1; ch = getchar(); }
while (isdigit(ch)) x = (x << 1) + (x << 3) + ch - '0', ch = getchar(); return x * flag;
}
int n, m, SS, SSS, TT;
int du[N];
int S, T, flow, cost;
struct edge { int u, v, c, w, next; }e[20001];
int head[N], tot = 1;
int dis[N], pre[N];
queue<int> q;
bool inq[N];
inline void insert(int u, int v, int c, int w) { e[++tot].u = u, e[tot].v = v, e[tot].c = c, e[tot].w = w, e[tot].next = head[u], head[u] = tot; }
inline void add(int u, int v, int c, int w) { insert(u, v, c, w), insert(v, u, 0, -w); }
inline bool spfa() {
rep(i, S, T) dis[i] = INF; dis[S] = 0; q.push(S);
while (!q.empty()) {
int u = q.front(); q.pop(); inq[u] = 0;
for (int i = head[u], v, w; i; i = e[i].next) if (e[i].c > 0 && dis[v = e[i].v] > dis[u] + (w = e[i].w)) {
dis[v] = dis[u] + w, pre[v] = i;
if (!inq[v]) q.push(v); inq[v] = 1;
}
}
return dis[T] != INF;
}
inline void mcf() {
int d = INF;
for (int i = T; (i ^ S); i = e[pre[i]].u) d = min(d, e[pre[i]].c);
flow += d;
for (int i = T; (i ^ S); i = e[pre[i]].u) e[pre[i]].c -= d, e[pre[i] ^ 1].c += d, cost += d * e[pre[i]].w;
}
int main() {
cin >> n >> m; SSS = 2 * n + 1, SS = SSS + 1, TT = SS + 1, T = TT + 1;
rep(i, 1, n) {
add(SSS, i, INF, 0), add(i + n, TT, INF, 0);
int V = read(); add(i, i + n, 0, 0);
du[i] -= V, du[i + n] += V;
}
add(SS, SSS, m, 0);
rep(i, 1, n) rep(j, i + 1, n) { int V = read(); if(V != -1) add(i + n, j, INF, V); }
add(TT, SS, INF, 0);
rep(i, 1, TT) if (du[i] > 0) add(S, i, du[i], 0); else add(i, T, -du[i], 0);
while (spfa()) mcf(); cout << cost;
return 0;
}
[bzoj2055] 80人環遊世界