昨天杭电多校1001题人均过,该学学网络流了(虽然dls说过,网络流只能出金牌题)
在b站看了电子科大的网络流入门,学会了dinic的板子,还不会严格证明
求单源单汇的最大流,简单来说就是只要残量网络能够到达汇点,就跑一遍增广路,然后再求残量网络,再跑增广路……直到汇点无法到达。
关键点:建反向边,残量网络通过分层图来判断,dinic优化
其中,dinic优化又分为当前弧优化、多路增广和炸点
当前弧优化貌似useless,多路增广就是将当前点能够走通的路全走一遍再返回,炸点就是把没用的点堵塞
最大流三题:
洛谷P3376 【模板】网络最大流
最大流的模板题
#include<bits/stdc++.h>
using namespace std;
#define fr first
#define se second
#define et0 exit(0);
#define rep(i, a, b) for(int i = (int)(a); i <= (int)(b); i ++)
#define rrep(i, a, b) for(int i = (int)(a); i >= (int)(b); i --)
#define IO ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
typedef unsigned long long ULL;
const int INF = 0X3f3f3f3f, N = 200 + 10, M = 5000 + 10, MOD = 1e9 + 7;
const double eps = 1e-7, pi = acos(-1);
int aim;
int dep[N];
int head[N], idx;
struct EGDE {
int to, next;
LL w;
} eg[M << 1];
void add(int x, int y, int w) {
eg[idx].to = y;
eg[idx].next = head[x];
eg[idx].w = w;
head[x] = idx++;
}
int bfs(int S, int T) {
queue<int> Q;
memset(dep, 0, sizeof dep);
dep[S] = 1;
Q.push(S);
while (!Q.empty()) {
int u = Q.front();
Q.pop();
for (int i = head[u]; ~i; i = eg[i].next) {
int to = eg[i].to;
if (eg[i].w && !dep[to]) {
dep[to] = dep[u] + 1;
Q.push(to);
}
}
}
return dep[T];
}
LL dfs(int u, LL rf) {
if (u == aim) return rf;
LL uf = 0;
for (int i = head[u]; ~i; i = eg[i].next) {
int to = eg[i].to;
if (eg[i].w && dep[to] == dep[u] + 1) {
LL tf = dfs(to, min(rf, eg[i].w));
eg[i].w -= tf, eg[i ^ 1].w += tf;
rf -= tf, uf += tf;
}
}
if (!uf) dep[u] = -2;
return uf;
}
LL maxflow(int S, int T) {
LL res = 0;
aim = T;
while (bfs(S, T)) res += dfs(S, 1ll << 31);
return res;
}
void work() {
int n, m, s, t;
memset(head, -1, sizeof head);
cin >> n >> m >> s >> t;
rep (i, 1, m) {
LL u, v, w;
cin >> u >> v >> w;
add(u, v, w), add(v, u, 0);
}
cout << maxflow(s, t) << endl;
}
signed main() {
IO
int test = 1;
// cin >> test;
while (test--) {
work();
}
return 0;
}
这题难就难在建图。
第\(i\)个队伍想要获胜,首先自己的胜场要尽可能多,也就是接下来跟自己有关的比赛全部获胜,设胜场为\(w_i\);
那么剩下的每个队伍胜场都不能超过\(w_i\),从每个队伍\(j\)向\(i\)连一条容量为\(w_i-w_j\)的边;
然后将队伍之间的比赛也当做若干个节点,从源点向比赛连一个边权为比赛数的边,再从比赛向两个队伍分别连边权为比赛数的边;
在边权的容量限制下,可以证明只要最大流为剩余比赛数,就一定有一种合法的比赛方案使第\(i\)队获胜。
#include<bits/stdc++.h>
using namespace std;
#define fr first
#define se second
#define et0 exit(0);
#define rep(i, a, b) for(int i = (int)(a); i <= (int)(b); i ++)
#define rrep(i, a, b) for(int i = (int)(a); i >= (int)(b); i --)
#define IO ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
typedef unsigned long long ULL;
const int INF = 0X3f3f3f3f, N = 1000 + 10, M = 2000 + 10, MOD = 1e9 + 7;
const double eps = 1e-7, pi = acos(-1);
int n;
int w[N], g[N][N];
int aim;
int dep[N];
int head[N], idx, gdx;
struct EGDE {
int to, next, w;
} eg[M << 1];
void add(int x, int y, int w) {
eg[idx].to = y;
eg[idx].next = head[x];
eg[idx].w = w;
head[x] = idx++;
}
int bfs(int S, int T) {
queue<int> Q;
memset(dep, 0, sizeof dep);
dep[S] = 1;
Q.push(S);
while (!Q.empty()) {
int u = Q.front();
Q.pop();
for (int i = head[u]; ~i; i = eg[i].next) {
int to = eg[i].to;
if (eg[i].w && !dep[to]) {
dep[to] = dep[u] + 1;
Q.push(to);
}
}
}
return dep[T];
}
int dfs(int u, int rf) {
if (u == aim) return rf;
int uf = 0;
for (int i = head[u]; ~i; i = eg[i].next) {
int to = eg[i].to;
if (eg[i].w && dep[to] == dep[u] + 1) {
int tf = dfs(to, min(rf, eg[i].w));
eg[i].w -= tf, eg[i ^ 1].w += tf;
rf -= tf, uf += tf;
}
}
if (!uf) dep[u] = -2;
return uf;
}
int maxflow(int S, int T) {
int res = 0;
aim = T;
while (bfs(S, T)) res += dfs(S, 1 << 20);
return res;
}
void work() {
int tmp;
cin >> n;
rep (i, 1, n) cin >> w[i] >> tmp;
rep (i, 1, n) rep (j, 1, n) cin >> g[i][j];
rep (i, 1, n) {
int sum = 0;
bool ok = true;
idx = 0, gdx = n;
memset(head, -1, sizeof head);
int wi = w[i];
rep (j, 1, n) wi += g[i][j];
rep (j, 1, n) {
if (j == i) continue;
if (wi < w[j]) {
ok = false;
break;
}
add(j, i, wi - w[j]), add(i, j, 0);
}
rep (j, 1, n) {
if (j == i) continue;
rep (k, j + 1, n) {
if (k == i) continue;
sum += g[j][k];
gdx++;
add(0, gdx, g[j][k]), add(gdx, 0, 0);
add(gdx, j, g[j][k]), add(j, gdx, 0);
add(gdx, k, g[j][k]), add(k, gdx, 0);
}
}
if (!ok) continue;
int t = maxflow(0, i);
if (t == sum) cout << i << " ";
}
cout << endl;
}
signed main() {
IO
int test = 1;
// cin >> test;
while (test--) {
work();
}
return 0;
}
杭电多校第十场 1001 Winner Prediction
跟上题类似,建图方式是一样的
#include<bits/stdc++.h>
using namespace std;
#define fr first
#define se second
#define et0 exit(0);
#define rep(i, a, b) for(int i = (int)(a); i <= (int)(b); i ++)
#define rrep(i, a, b) for(int i = (int)(a); i >= (int)(b); i --)
#define IO ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
typedef unsigned long long ULL;
const int INF = 0X3f3f3f3f, N = 2000 + 10, M = 5000 + 10, MOD = 1e9 + 7;
const double eps = 1e-7, pi = acos(-1);
int n;
int w[N];
int aim;
int dep[N];
int head[N], idx, gdx;
struct EGDE {
int to, next, w;
} eg[M << 1];
void add(int x, int y, int w) {
eg[idx].to = y;
eg[idx].next = head[x];
eg[idx].w = w;
head[x] = idx++;
}
int bfs(int S, int T) {
queue<int> Q;
memset(dep, 0, sizeof dep);
dep[S] = 1;
Q.push(S);
while (!Q.empty()) {
int u = Q.front();
Q.pop();
for (int i = head[u]; ~i; i = eg[i].next) {
int to = eg[i].to;
if (eg[i].w && !dep[to]) {
dep[to] = dep[u] + 1;
Q.push(to);
}
}
}
return dep[T];
}
int dfs(int u, int rf) {
if (u == aim) return rf;
int uf = 0;
for (int i = head[u]; ~i; i = eg[i].next) {
int to = eg[i].to;
if (eg[i].w && dep[to] == dep[u] + 1) {
int tf = dfs(to, min(rf, eg[i].w));
eg[i].w -= tf, eg[i ^ 1].w += tf;
rf -= tf, uf += tf;
}
}
if (!uf) dep[u] = -2;
return uf;
}
int maxflow(int S, int T) {
int res = 0;
aim = T;
while (bfs(S, T)) res += dfs(S, 1 << 27);
return res;
}
void work() {
int sum = 0, m1, m2;
bool ok = true;
idx = 0;
memset(head, -1, sizeof head);
cin >> n >> m1 >> m2;
gdx = n;
rep (i, 1, n) w[i] = 0;
rep (i, 1, m1) {
int x, y, z;
cin >> x >> y >> z;
if (z) w[x]++;
else w[y]++;
}
rep (i, 1, m2) {
int x, y;
cin >> x >> y;
if (x == 1 || y == 1) w[1]++;
else {
sum++;
gdx++;
add(0, gdx, 1), add(gdx, 0, 0);
add(gdx, x, 1), add(x, gdx, 0);
add(gdx, y, 1), add(y, gdx, 0);
}
}
int w1 = w[1];
rep (i, 2, n) {
if (w1 < w[i]) {
ok = false;
break;
}
add(i, 1, w1 - w[i]), add(1, i, 0);
}
if (!ok) {
cout << "NO" << endl;
return;
}
int t = maxflow(0, 1);
if (t == sum) cout << "YES" << endl;
else cout << "NO" << endl;
rep (i, 0, n) w[i] = 0;
}
signed main() {
IO
memset(head, -1, sizeof head);
int test = 1;
cin >> test;
while (test--) {
work();
}
return 0;
}
标签:最大,gdx,int,eg,网络,dep,add,rep,流三题
From: https://www.cnblogs.com/xhy666/p/16606940.html