P6906 [ICPC2015 WF] Catering
XIX. P6906 [ICPC2015 WF] Catering
比较简单的网络流。
拆点限制每个点只能经过一次。
我们发现直接流
避免上下界网络流的方法:我们知道
#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define TIME 1e3 * clock() / CLOCKS_PER_SEC
using ll = long long;
using uint = unsigned int;
using lll = __int128;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
using ull = unsigned long long;
inline ll read() {
ll x = 0, sgn = 0;
char s = getchar();
while(!isdigit(s)) sgn |= s == '-', s = getchar();
while(isdigit(s)) x = x * 10 + s - '0', s = getchar();
return sgn ? -x : x;
}
inline void print(int x) {
if(x < 0) return putchar('-'), print(-x);
if(x >= 10) print(x / 10);
putchar(x % 10 + '0');
}
bool Mbe;
constexpr int N = 200 + 5;
constexpr int M = 1e4 + 5;
constexpr int inf = 1e7;
struct flow {
int cnt = 1, hd[N], nxt[M << 1], to[M << 1], limit[M << 1], cst[M << 1];
void add(int u, int v, int w, int c) {
nxt[++cnt] = hd[u], hd[u] = cnt, to[cnt] = v, limit[cnt] = w, cst[cnt] = c;
nxt[++cnt] = hd[v], hd[v] = cnt, to[cnt] = u, limit[cnt] = 0, cst[cnt] = -c;
}
int in[N], dis[N], fr[N];
int mincost(int S, int T) {
int cost = 0;
while(1) {
queue<int> q;
memset(dis, 0x3f, sizeof(dis));
dis[S] = 0, q.push(S);
while(!q.empty()) {
int t = q.front();
q.pop(), in[t] = 0;
for(int i = hd[t]; i; i = nxt[i]) {
int it = to[i], d = dis[t] + cst[i];
if(limit[i] && d < dis[it]) {
dis[it] = d, fr[it] = i;
if(!in[it]) q.push(it), in[it] = 1;
}
}
}
if(dis[T] > 1e9) return cost;
int fl = 1064;
for(int i = T; i != S; i = to[fr[i] ^ 1]) fl = min(fl, limit[fr[i]]);
for(int i = T; i != S; i = to[fr[i] ^ 1]) limit[fr[i]] -= fl, limit[fr[i] ^ 1] += fl;
cost += fl * dis[T];
}
}
} g;
int n, k;
bool Med;
int main() {
fprintf(stderr, "%.3lf MB\n", (&Mbe - &Med) / 1048576.0);
#ifdef ALEX_WEI
FILE* IN = freopen("1.in", "r", stdin);
FILE* OUT = freopen("1.out", "w", stdout);
#endif
cin >> n >> k;
int T = n * 2 + 2;
for(int i = 0; i < n; i++)
for(int j = i + 1; j <= n; j++)
g.add(i * 2 + 1, j * 2, 1, read());
for(int i = 1; i <= n; i++) g.add(i * 2, i * 2 + 1, 1, -inf), g.add(i * 2 + 1, T, 1, 0);
int ans = 1e9, cur = 0;
for(int i = 1; i <= k; i++) {
g.add(0, 1, 1, 0);
ans = min(ans, cur += g.mincost(0, T));
}
cout << ans + inf * n << endl;
cerr << TIME << " ms\n";
return 0;
}
/*
2022/9/25
author: Alex_Wei
start coding at 7:52
finish debugging at 8:15
*/