网络流

各种建图方法:
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;
}
posted @ 2022-09-08 22:26  yyx525jia  阅读(11)  评论(0)    收藏  举报