网络流
各种建图方法:
https://www.cnblogs.com/birchtree/p/12912607.html
P3376 【模板】网络最大流(dicnic+当前弧优化+分层图)
#include <bits/stdc++.h>
#define for1(i,a,b) for(ll i = a;i<=b;i++)
#define ll long long
#define mp(a,b) make_pair(a,b)
using namespace std;
struct node {
int from;
int to;
int w;
int nex;
} a[500005];
const ll inf = 1e9;
ll n, m, s, t, vis[500005], hd[500005], ans, ra[500005];
ll cnt = 1;//注意cnt=0就会错
queue <int > dl;
void ru(ll x, ll y, ll z) {
a[++cnt].from = x;
a[cnt].to = y;
a[cnt].w = z;
a[cnt].nex = hd[x];
hd[x] = cnt;
}
bool bfs() {
memset(vis, 0, sizeof(vis));
vis[s] = 1;
dl.push(s);
while (!dl.empty()) {
ll x = dl.front();
dl.pop();
ra[x] = hd[x]; //回到初始状态
for (int i = hd[x]; i; i = a[i].nex) {
ll y = a[i].to;
if (!vis[y] && a[i].w) //如果没有访问过并且流量不为0
vis[y] = vis[x] + 1 //记录深度(优化1)
, dl.push(y);
}
}
return vis[t] != 0; //最后有没有到达汇点
}
ll dfs(int now, int can) { //当前到达的节点以及剩余的流量
if (now == t)
return can;//到达汇点就回溯
int ji = can;
for (int i = ra[now]; i; i = a[i].nex) {
int y = a[i].to;
ra[now] = i; //剪枝(?)(优化2)
if (vis[y] == vis[now] + 1 &&
a[i].w) { //是否是从深度低的地方流过来的(优化1)以及流量不为0
ll real = min(ji, a[i].w); //实际能流走的量
ll ji2 = dfs(y, real); //找到最后减少的量
a[i].w -= ji2, a[i ^ 1].w +=
ji2; //若i为正向边则i^1就是反向边 ,若i为反向边则i^1就是正向边
ji -= ji2; //分流
if (!ji)
break ;//流完了
}
}
return can - ji; //实际需要的流量
}
int main() {
ll x, y, z;
scanf("%lld%lld%lld%lld", &n, &m, &s, &t);
for1(i, 1, m) {
scanf("%lld%lld%lld", &x, &y, &z);
ru(x, y, z);
ru(y, x, 0); //建反向边
}
while (bfs()) {
ans += dfs(s, inf);
}
printf("%lld\n", ans);
return 0;
}
P3381 【模板】最小费用最大流(spfa+dicnid分层图)
#include <bits/stdc++.h>
#define ll long long
#define for1(i,a,b) for(register int i = a;i <= b;i++)
using namespace std;
const ll inf = 0x3f3f3f3f3f3f3f3f;
const int maxn = 500005;
int n, m, s, t, hd[maxn], cnt = 1, ra[maxn];
ll dis[maxn], ans, ans2;
bool spfa[maxn], vis[maxn];
struct node {
int to;
ll w;
ll cost;
int nex;
} a[maxn];
void add(int x, int y, int w, int c) {
a[++cnt].to = y;
a[cnt].w = w;
a[cnt].cost = c;
a[cnt].nex = hd[x];
hd[x] = cnt;
}
bool SPFA() {
queue <int> q;
q.push(s);
memset(spfa, 0, sizeof(spfa));
memset(dis, 0x3f, sizeof(dis));
spfa[s] = 1;
dis[s] = 0;
while (!q.empty()) {
int x = q.front();
q.pop();
spfa[x] = 0;
for (int i = hd[x]; i; i = a[i].nex) {
int v = a[i].to;
if (a[i].w && dis[v] > dis[x] + a[i].cost) {
dis[v] = dis[x] + a[i].cost;
if (!spfa[v]) {
q.push(v);
spfa[v] = 1;
}
}
}
}
return dis[t] != inf;
}
ll dfs(int now, ll w)
{
if (now == t || w == 0)
return w;
vis[now] = 1;
ll ji = w;
for (int i = ra[now]; i; i = a[i].nex)
{
int v = a[i].to;
ra[now] = i;
if (a[i].w && !vis[v] && dis[now] + a[i].cost == dis[v])
{
ll real = min(ji,a[i].w);
ll ji2 = dfs(v, real);
if (ji2) {
a[i].w -= ji2;
a[i ^ 1].w += ji2;
ji -= ji2;
ans2 += a[i].cost * ji2;
}
if(!ji) break;
}
}
vis[now] = 0;
if (w - ji == 0)
vis[now] = 1;
return w-ji;
}
void dinic() {
while (SPFA())
{
ll d;
memset(vis, 0, sizeof(vis));
for1(i,1,n)
ra[i] = hd[i];
d = dfs(s, inf);
if (d != 0)
ans += d;
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n >> m >> s >> t;
int x,y,w,c;
for1(i,1,m)
{
cin >> x >> y >> w >> c;
add(x, y, w, c);
add(y, x, 0, -c);
}
dinic();
cout << ans << ' ' << ans2 << '\n';
return 0;
}
之前一直都没写(悲
今天下午突击一下网络流24题,看看能写多少题
P2756 飞行员配对方案问题
就是二分图最大匹配求方案数,网络流似乎比匈牙利快?不过空间要大不少
#include<bits/stdc++.h>
#define for1(i,a,b) for(register ll i = a;i <= b;i ++)
#define ll long long
using namespace std;
const ll maxn = 5e5 + 5;
const ll inf = 1e9 + 7;
struct node
{
ll nex;
ll from;
ll to;
ll w;
ll tag;
}a[maxn<<2];
ll hd[maxn],cnt = 1,ra[maxn];
ll w[maxn] , vis[maxn],n,m,s,t;
ll ans,e;
void ru(ll x , ll y, ll z,ll xx)
{
a[++cnt].to = y;
a[cnt].w = z;
a[cnt].from = x;
a[cnt].tag = xx;
a[cnt].nex = hd[x];
hd[x] = cnt;
return ;
}
bool bfs()
{
queue<ll>dl;
memset(vis,0,sizeof(vis));
dl.push(s);
vis[s] = 1;
while(!dl.empty())
{
ll x = dl.front();
dl.pop();
ra[x] = hd[x];
for(ll i = hd[x];i;i = a[i].nex)
{
ll v = a[i].to;
if(vis[v] == 0 && a[i].w)
{
vis[v] = vis[x] + 1;
dl.push(v);
}
}
}
return vis[t] != 0;
}
ll dfs(ll now, ll can)
{
if(now == t) return can;
ll ji = can;
for(ll i = ra[now];i;i = a[i].nex)
{
ll v = a[i].to;
ra[now] = i;
if(vis[v] == vis[now] + 1 && a[i].w)
{
ll real = min(a[i].w,ji);
ll ji2 = dfs(v,real);
a[i].w-= ji2,a[i ^ 1].w += ji2;
ji -= ji2;
if(!ji) break;
}
}
return can - ji;
}
int main()
{
// ios::sync_with_stdio(false);
// cin.tie(nullptr);
cin >> n >> m;
s = 0,t = n + m + 1;
for1(i,1,n)
{
ru(0,i,1,0);
ru(i,0,0,0);
}
for1(i,1,m)
{
ru(i + n , n + m + 1, 1,0);
ru(n + m + 1, n + i, 0,0);
}
ll x,y,z;
while(1)
{
cin >> x >> y;
if(x == -1 && y == -1) break;
ru(x,y,1,1);
ru(y,x,0,0);
}
while(bfs())
{
ans += dfs(s,inf);
}
cout << ans << '\n';
for1(i,1,cnt)
if(a[i].tag == 1 && a[i].w == 0)
cout << a[i].from << ' ' << a[i].to << '\n';
return 0;
}
P4011 孤岛营救问题
?以前写过了,而且和网络流一点关系没有,找了好久也没找到这个怎么用网络流写
#include<bits/stdc++.h>
#define for1(i,a,b) for(register ll i = a;i <= b;i ++)
#define ll long long
using namespace std;
const ll maxn = 5e5 + 5;
const ll inf = 1e9 + 7;
struct node
{
ll nex;
ll from;
ll to;
ll w;
ll tag;
}a[maxn<<2];
ll hd[maxn],cnt = 1,ra[maxn];
ll w[maxn] , vis[maxn],n,m,s,t;
ll ans,e;
void ru(ll x , ll y, ll z,ll xx)
{
a[++cnt].to = y;
a[cnt].w = z;
a[cnt].from = x;
a[cnt].tag = xx;
a[cnt].nex = hd[x];
hd[x] = cnt;
return ;
}
bool bfs()
{
queue<ll>dl;
memset(vis,0,sizeof(vis));
dl.push(s);
vis[s] = 1;
while(!dl.empty())
{
ll x = dl.front();
dl.pop();
ra[x] = hd[x];
for(ll i = hd[x];i;i = a[i].nex)
{
ll v = a[i].to;
if(vis[v] == 0 && a[i].w)
{
vis[v] = vis[x] + 1;
dl.push(v);
}
}
}
return vis[t] != 0;
}
ll dfs(ll now, ll can)
{
if(now == t) return can;
ll ji = can;
for(ll i = ra[now];i;i = a[i].nex)
{
ll v = a[i].to;
ra[now] = i;
if(vis[v] == vis[now] + 1 && a[i].w)
{
ll real = min(a[i].w,ji);
ll ji2 = dfs(v,real);
a[i].w-= ji2,a[i ^ 1].w += ji2;
ji -= ji2;
if(!ji) break;
}
}
return can - ji;
}
int main()
{
// ios::sync_with_stdio(false);
// cin.tie(nullptr);
cin >> n >> m;
s = 0,t = n + m + 1;
for1(i,1,n)
{
ru(0,i,1,0);
ru(i,0,0,0);
}
for1(i,1,m)
{
ru(i + n , n + m + 1, 1,0);
ru(n + m + 1, n + i, 0,0);
}
ll x,y,z;
while(1)
{
cin >> x >> y;
if(x == -1 && y == -1) break;
ru(x,y,1,1);
ru(y,x,0,0);
}
while(bfs())
{
ans += dfs(s,inf);
}
cout << ans << '\n';
for1(i,1,cnt)
if(a[i].tag == 1 && a[i].w == 0)
cout << a[i].from << ' ' << a[i].to << '\n';
return 0;
}

浙公网安备 33010602011771号