luogu P4553 80人环游世界
https://www.luogu.com.cn/problem/P4553
容易想到拆点建二分图,跑最小费用路径覆盖,不过要强制每个点都流满
于是把 i − > i + n , c i->i+n,c i−>i+n,c表示这个点必须要被经过c次
然后跑最小费用可行流即可
code:
#include<bits/stdc++.h>
#define N 805
#define ll long long
using namespace std;
struct edge {
int v, c, nxt;
ll w;
} e[N * N << 1];
int p[N], eid;
void init() {
memset(p, -1, sizeof p);
eid = 0;
}
void insert(int u, int v, int c, ll w) {
e[eid].v = v;
e[eid].c = c;
e[eid].w = w;
e[eid].nxt = p[u];
p[u] = eid ++;
}
void add(int u, int v, int c, ll w) { //printf("%d --> %d %d %d\n", u, v, c, w);
insert(u, v, c, w), insert(v, u, 0, -w);
}
int n, m, S, T, pre[N], vis[N];
ll dis[N];
queue<int> q;
const ll INF = 1e18;
const int inf = 1e4;
int bfs() {
for(int i = 0; i <= T; i ++) dis[i] = INF, vis[i] = 0, pre[i] = -1;
dis[S] = 0; q.push(S);
while(q.size()) {
int u = q.front(); q.pop();
vis[u] = 0;
for(int i = p[u]; i + 1; i = e[i].nxt) {
int v = e[i].v; //printf("*%d %d %d %d %d %d\n", u, v, dis[u], dis[v], e[i].c, e[i].w);
if(e[i].c && dis[u] + e[i].w < dis[v]) {
dis[v] = dis[u] + e[i].w;
pre[v] = i;
if(!vis[v]) vis[v] = 1, q.push(v);
}
}
}
// for(int i = 1; i <= T; i ++) printf("%lld ", dis[i]); printf("\n");
return pre[T] != -1;
}
ll mcfc() {
ll ret = 0;
for(; bfs() ;) {
ll flow = INF;
for(int i = T; i != S; i = e[pre[i] ^ 1].v) flow = min(flow, (ll)e[pre[i]].c);
for(int i = T; i != S; i = e[pre[i] ^ 1].v) {
ret += flow * e[pre[i]].w;
e[pre[i]].c -= flow, e[pre[i] ^ 1].c += flow;
}
// printf("*%d*", flow);
// break;
}
return ret;
}
ll sum[N], totc;
void addl(int u, int v, int l, int r, int c) { //printf("%d-->%d %d %d %d\n", u, v, l, r, c);
if(r - l > 0) add(u, v, r - l, c);
sum[u] -= l, sum[v] += l; totc += 1ll * c * l;
}
int SS, TT;
void build() {
for(int i = 1; i <= TT; i ++) {
if(sum[i] > 0) add(S, i, sum[i], 0);
if(sum[i] < 0) add(i, T, - sum[i], 0);
}
// for(int i = 1; i <= TT; i ++) printf(" %lld ", sum[i]); printf("\n");
add(TT, SS, m, 0);
}
int main() {
init();
scanf("%d%d", &n, &m);
SS = 2 * n + 1, TT = SS + 1, S = TT + 1, T = S + 1;
for(int i = 1, c; i <= n; i ++) {
scanf("%d", &c);
addl(SS, i, 0, inf, 0);
addl(i, i + n, c, c, 0);
addl(i + n, TT, 0, inf, 0);
}
for(int i = 1; i <= n; i ++)
for(int j = i + 1, c; j <= n; j ++) {
scanf("%d", &c);
if(c >= 0) addl(i + n, j, 0, inf, c);
}
build();
// printf("%d %d\n", S, T);
printf("%lld", mcfc() + totc);
return 0;
}