@ZCDHJ
2018-09-28T13:50:19.000000Z
字数 1927
阅读 684
网络流
费用流模板题。
将每个点拆成一个入点和一个出点,在入点与出点间连一条容量为 ,费用为点权的边,再连一条容量为 ,费用为 的边。然后再在相邻的点之间连边就行了。然后直接跑最大费用最大流。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
const int INF = 0x3f3f3f3f;
const int MIINF = 0xcfcfcfcf;
const int MAXN = 100;
const int MAXM = 8 * MAXN * MAXN - 4 * MAXN;
int n, k, edge = -1, maxCost, sp, ep;
int firstEdge[MAXN * MAXN | 1], lst[MAXN * MAXN | 1], dist[MAXN * MAXN | 1], minFlow[MAXN * MAXN << 1], g[MAXN | 1][MAXN | 1];
struct Edge {
int to, f, w, nxt;
Edge(){}
Edge(int a, int b, int c, int d) {
to = b;
f = c;
w = d;
nxt = firstEdge[a];
}
} e[MAXM + 2];
inline int read() {
register int x = 0;
register char ch = getchar();
while(!isdigit(ch)) ch = getchar();
while(isdigit(ch)) {
x = x * 10 + ch - '0';
ch = getchar();
}
return x;
}
inline void addEdge(int a, int b, int c, int d) {
e[++edge] = Edge(a, b, c, d);
firstEdge[a] = edge;
}
bool Augment() {
std::queue <int> q;
bool vis[MAXN * MAXN << 1];
while(!q.empty()) q.pop();
memset(vis, false, sizeof(vis));
memset(dist, MIINF, sizeof(dist));
dist[sp] = 0;
minFlow[sp] = INF;
q.push(sp);
do {
int from = q.front();
q.pop();
vis[from] = false;
for(int k = firstEdge[from]; ~k; k = e[k].nxt) {
int to = e[k].to, f = e[k].f, w = e[k].w;
if(f > 0 && dist[to] < dist[from] + w) {
dist[to] = dist[from] + w;
minFlow[to] = std::min(minFlow[from], f);
lst[to] = k;
if(!vis[to]) {
q.push(to);
vis[to] = true;
}
}
}
} while(!q.empty());
return dist[ep] != MIINF;
}
int EK(int flow) {
while(flow > 0 && Augment()) {
maxCost += minFlow[ep] * dist[ep];
int tmp = ep;
while(tmp != sp) {
e[lst[tmp]].f -= minFlow[ep];
e[lst[tmp] ^ 1].f += minFlow[ep];
tmp = e[lst[tmp] ^ 1].to;
}
}
}
inline int ID(int x, int y, int z) {
return (x - 1) * n + y + z * n * n;
}
int main() {
n = read();
k = read();
sp = 1;
ep = n * n << 1;
memset(firstEdge, -1, sizeof(firstEdge));
for(int i = 1; i <= n; ++i) {
for(int j = 1; j <= n; ++j) {
int val = read();
addEdge(ID(i,j, 0), ID(i, j, 1), 1, val);
addEdge(ID(i, j, 1), ID(i, j, 0), 0, -val);
addEdge(ID(i, j, 0), ID(i, j, 1), k - 1, 0);
addEdge(ID(i, j, 1), ID(i, j, 0), 0, 0);
if(j < n) {
addEdge(ID(i, j, 1), ID(i, j + 1, 0), k, 0);
addEdge(ID(i, j + 1, 0), ID(i, j, 1), 0, 0);
}
if(i < n) {
addEdge(ID(i, j, 1), ID(i + 1, j, 0), k, 0);
addEdge(ID(i + 1, j, 0), ID(i, j, 1), 0, 0);
}
}
}
EK(k);
printf("%d\n", maxCost);
return 0;
}