网络流与线性规划24题做题笔记
感觉不知道做啥了 练练网络流
汽车加油行驶问题
绝大多数人的第一道24题 因为是披着网络流皮的最短路
建分层图 第 \(k\) 层表示当前剩余油量为 \(k\)
往右/下移动费用为 \(0\) 剩下两个方向费用为 \(B\)
对于没有加油站的点 往第 \(K\) 层同一位置连边 费用为 \(A + C\)
对于有加油站的点 所有不在第 \(K\) 层的点不往四个方向连边 只向第 \(K\) 层连一条费用为 \(A\) 的边
对起点和终点建电梯 费用为 \(0\)
所有边的流量均为 \(1\) 跑最小费用最大流即可
发现最大流一定为 \(1\) 所以实际上就是最短路
点击查看代码
#include <bits/stdc++.h>
#define ll long long
#define int long long
using namespace std;
inline int read() {
int xr = 0, F = 1;
char cr;
while (cr = getchar(), cr < '0' || cr > '9') if (cr == '-') F = -1;
while (cr >= '0' && cr <= '9')
xr = (xr << 1) + (xr << 3) + (cr ^ 48), cr = getchar();
return xr * F;
}
namespace steven24 {
const int N = 2e6 + 0721;
const int inf = 0x7fffffff;
int mp[105][105];
int dx[4] = {1, -1, 0, 0};
int dy[4] = {0, 0, 1, -1};
int n, k, A, B, C;
struct network_flows {
int minc[N], incf[N], pre[N];
int head[N], f[N], cost[N], to[N], nxt[N];
int cnt = 1;
int maxflow, mincost;
int S, T;
inline void add_edge(int x, int y, int c, int flow) {
to[++cnt] = y;
nxt[cnt] = head[x];
head[x] = cnt;
f[cnt] = flow;
cost[cnt] = c;
to[++cnt] = x;
nxt[cnt] = head[y];
head[y] = cnt;
f[cnt] = 0;
cost[cnt] = -c;
}
bool exist[N];
queue<int> q;
bool spfa() {
while (!q.empty()) q.pop();
for (int i = 0; i <= n * n * (k + 1) + 1; ++i) {
minc[i] = inf;
exist[i] = 0;
}
exist[S] = 1;
minc[S] = 0;
incf[S] = inf;
q.push(S);
while (!q.empty()) {
int now = q.front();
q.pop();
exist[now] = 0;
for (int i = head[now]; i; i = nxt[i]) {
if (!f[i]) continue;
int y = to[i];
if (minc[y] > minc[now] + cost[i]) {
minc[y] = minc[now] + cost[i];
pre[y] = i;
incf[y] = min(incf[now], f[i]);
if (!exist[y]) exist[y] = 1, q.push(y);
}
}
}
if (minc[T] == inf) return 0;
else return 1;
}
void MCMF() {
while (spfa()) {
int x = T;
maxflow += incf[T];
mincost += incf[T] * minc[T];
int i;
while (x != S) {
i = pre[x];
f[i] -= incf[T];
f[i ^ 1] += incf[T];
x = to[i ^ 1];
}
}
}
} G;
inline int change(int x, int y) {
return (x - 1) * n + y;
}
bool exist(int x, int y) {
return x >= 1 && x <= n && y >= 1 && y <= n;
}
void main() {
n = read(), k = read(), A = read(), B = read(), C = read();
for (int i = 1; i <= n; ++i) for (int j = 1; j <= n; ++j) mp[i][j] = read();
G.S = 1 + (k + 1) * n * n;
G.add_edge(G.S, change(1, 1) + k * n * n, 0, 1);
G.T = 0;
G.add_edge(change(n, n), G.T, 0, 1);
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
int id = change(i, j);
if (mp[i][j]) {
for (int s = 0; s < k; ++s) G.add_edge(id + n * n * s, id + n * n * k, A, 1);
for (int s = 0; s < 4; ++s) {
int x = i + dx[s], y = j + dy[s];
if (!exist(x, y)) continue;
if (dx[s] < 0 || dy[s] < 0) G.add_edge(id + n * n * k, change(x, y) + (k - 1) * n * n, B, 1);
else G.add_edge(id + n * n * k, change(x, y) + (k - 1) * n * n, 0, 1);
}
} else {
for (int s = 1; s <= k; ++s) {
for (int p = 0; p < 4; ++p) {
int x = i + dx[p], y = j + dy[p];
if (!exist(x, y)) continue;
if (dx[p] < 0 || dy[p] < 0) G.add_edge(id + n * n * s, change(x, y) + (s - 1) * n * n, B, 1);
else G.add_edge(id + n * n * s, change(x, y) + (s - 1) * n * n, 0, 1);
}
}
for (int s = 0; s < k; ++s) G.add_edge(id + n * n * s, id + n * n * k, A + C, 1);
}
}
}
for (int i = 1; i <= k; ++i) G.add_edge(change(n, n) + n * n * i, change(n, n), 0, 1);
G.MCMF();
printf("%lld\n", G.mincost);
}
}
signed main() {
steven24::main();
return 0;
}
圆桌问题
见代码开头部分
点击查看代码
/*
起点往每个单位连流量为r的边
每个单位往每个桌连流量为1的边(桌 = id + m)
每个桌往终点连流量为c的边(T = n + m + 1)
跑最大流
*/
#include <bits/stdc++.h>
#define ll long long
using namespace std;
inline int read() {
int xr = 0, F = 1;
char cr;
while (cr = getchar(), cr < '0' || cr > '9') if (cr == '-') F = -1;
while (cr >= '0' && cr <= '9')
xr = (xr << 1) + (xr << 3) + (cr ^ 48), cr = getchar();
return xr * F;
}
namespace steven24 {
const int N = 521;
const int M = 1e5 + 0721;
const int inf = 0x7fffffff;
int head[N], nxt[M], to[M], fl[M], cnt = 1;
int dis[N], cur[N];
int r[N], cc[N];
int n, m, S, T;
vector<int> ans[N];
inline void add_edge(int x, int y, int z) {
to[++cnt] = y;
nxt[cnt] = head[x];
head[x] = cnt;
fl[cnt] = z;
to[++cnt] = x;
nxt[cnt] = y;
head[y] = cnt;
fl[cnt] = z;
}
bool bfs() {
queue<int> q;
for (int i = 0; i <= n + m + 1; ++i) dis[i] = -1;
for (int i = 0; i <= n + m + 1; ++i) cur[i] = head[i];
dis[S] = 0;
q.push(S);
while (!q.empty()) {
int now = q.front();
q.pop();
if (now == T) return 1;
for (int i = head[now]; i; i = nxt[i]) {
int y = to[i];
if (fl[i] > 0 && dis[y] == -1) {
dis[y] = dis[now] + 1;
q.push(y);
}
}
}
return 0;
}
int dinic(int x, int res) {
if (!res || x == T) return res;
int flow = 0, c;
for (int i = cur[x]; i && res > 0; i = nxt[i]) {
cur[x] = i;
int y = to[i];
if (fl[i] > 0 && dis[y] == dis[x] + 1) {
c = dinic(y, min(res, fl[i]));
if (!c) dis[y] = -1;
fl[i] -= c;
fl[i ^ 1] += c;
res -= c;
flow += c;
}
}
return flow;
}
void build_map() {
S = 0, T = n + m + 1;
for (int i = 1; i <= m; ++i) add_edge(S, i, r[i]);
for (int i = 1; i <= m; ++i) {
for (int j = 1; j <= n; ++j) add_edge(i, j + m, 1);
}
for (int j = 1; j <= n; ++j) add_edge(j + m, T, cc[j]);
}
void main() {
m = read(), n = read();
int sum = 0;
for (int i = 1; i <= m; ++i) {
r[i] = read();
sum += r[i];
}
for (int i = 1; i <= n; ++i) cc[i] = read();
build_map();
int maxflow = 0;
while (bfs()) maxflow += dinic(S, inf);
if (maxflow < sum) puts("0");
else {
puts("1");
for (int i = 1; i <= m; ++i) {
for (int j = head[i]; j; j = nxt[j]) {
int y = to[j] - m;
// cout << i << " " << y << " " << fl[j] << "\n";
if (!fl[j] && y > 0) printf("%d ", y);
}
printf("\n");
}
}
}
}
int main() {
steven24::main();
return 0;
}
/*
4 5
4 5 3 5
3 5 2 6 4
*/

浙公网安备 33010602011771号