P3376 網路流【模板】

Euan?發表於2024-08-04

網路:任意一張有向圖,其中有N個點,M條邊,源點S,匯點T
我們把c(x,y)稱為容量,
把f(x,y)稱為流量。

流函式的三大性質:

容量限制:每條邊的流量總不可能大於該邊的容量
f(x,y)<=c(x,y)
斜對稱:正向邊的流量=反向邊的流量
f(x,y)=-f(y,x)
流量守恆:正向的所有流量和=反向的所有流量和
Any x!=S,x!=T,∑(u,x)∈E f(u,x)=∑(x,v)∈E f(x,v)

在任意時刻,網路中所有節點以及剩餘容量大於0的邊構成的子圖被稱為殘量網路.
合法的流函式有很多,其中使得整個網路流量之和最大的流函式稱為網路的最大流,此時的流量和被稱為網路的最大流量
EK演算法:
若一條從S到T的路徑上所有邊的剩餘容量都大於0,則稱這樣的路徑為一條增廣路
EK演算法的思想就是不斷用BFS尋找增廣路並不斷更新最大流量值,直到網路上不存在增廣路為止
我們不斷尋找剩餘流量大於零的邊,尋找從S到T的路徑,計算路徑上各邊剩餘容量值的最小值dis,則網路的最大流量就可以增加dis,
(經過的正向邊容量值全部減去dis,反向邊全部加上dis)
反向邊:給程式一個反悔的機會,防止直接更改值影響到之後尋找另外的增廣路

我們新增正向邊的同時新增反向邊,更新邊權的時候,我們就可以直接使用xor1的方式,找到對應的正向邊和反向邊(奇數異或1相當於-1,偶數異或1相當於+1)

程式碼:

點選檢視程式碼
#include<bits/stdc++.h>
using namespace std;
const int N=501000;
long long n,m,s,t;
struct node{
	long long next,v,w;
}e[N];
long long tot=1,vis[N],pre[N],head[N],flag[2506][2506];
long long ans,dis[N];
long long bfs(){
	for(int i=1;i<=n;i++) vis[i]=0;
	queue <long long> q;
	q.push(s);
	vis[s]=1;
	dis[s]=0x3f3f3f3f;
	while(!q.empty()){
		long long x=q.front();
		q.pop();
		for(int i=head[x];i;i=e[i].next){
			if(!e[i].w) continue;
			long long v=e[i].v;
			if(vis[v]) continue;
			dis[v]=min(dis[x],e[i].w);
			pre[v]=i;
			q.push(v);
			vis[v]=1;
			if(v==t) return 1;
		}
	}
	return 0;
}
void update(){
	long long x=t;
	while(x!=s){
		long long v=pre[x];
		e[v].w-=dis[t];
		e[v^1].w+=dis[t];
		x=e[v^1].v;
	}
	ans+=dis[t];
}
void add(long long u,long long v,long long w){
	e[++tot].v=v;
	e[tot].w=w;
	e[tot].next=head[u];
	head[u]=tot;
	e[++tot].v=u;
	e[tot].w=0;
	e[tot].next=head[v];
	head[v]=tot;
}
int main(){
	cin>>n>>m>>s>>t;
	for(int i=1;i<=m;i++){
		int u,v,w;
		cin>>u>>v>>w;
		if(!flag[u][v]){
			add(u,v,w);
			flag[u][v]=tot;
		}
		else{
			e[flag[u][v]-1].w+=w;
		}
	}
	while(bfs()!=0){
		update();
	}
	cout<<ans<<endl;
	return 0;
} 

Dinic
應用BFS生成分層圖,然後用DFS實現多路增廣。
程式碼:

點選檢視程式碼
#include<bits/stdc++.h>
using namespace std;
const long long INF=2019202408;
const int N=500010;
long long n,m,s,t;
long long tot=1,head[N];
struct node{
	long long v,w,next;
}e[N<<2];
long long flag[2600][2600];
long long d[N];
long long vis[N],dis[N],now[N];
long long ans;
int bfs(){
	for(int i=1;i<=n;i++) dis[i]=INF;
	queue<long long> q;
	q.push(s);
	dis[s]=0;
	now[s]=head[s];
	while(q.size()){
		long long x=q.front();
		q.pop();
		for(int i=head[x];i;i=e[i].next){
			int v=e[i].v;
			if(e[i].w>0&&dis[v]==INF){
				q.push(v);
				now[v]=head[v];
				dis[v]=dis[x]+1;
				if(v==t) return 1;
			}
		}
	}
	return 0;
}
int dfs(int x,long long sum){
	if(x==t) return sum;
	int k,res=0;
	for(int i=now[x];i&&sum;i=e[i].next){
		now[x]=i;
		int v=e[i].v;
		if(e[i].w>0&&(dis[v]==dis[x]+1)){
			k=dfs(v,min(sum,e[i].w));
			if(k==0) dis[v]=INF;
			e[i].w-=k;
			e[i^1].w+=k;
			res+=k;
			sum-=k;
		}
	}
	return res;
}
void add(int u,int v,long long w){
	e[++tot].v=v;
	e[tot].w=w;
	e[tot].next=head[u];
	head[u]=tot;
	e[++tot].v=u;
	e[tot].w=0;
	e[tot].next=head[v];
	head[v]=tot;
	return ;
}
int main(){
	cin>>n>>m>>s>>t;
	for(int i=1;i<=m;i++){
		int u,v,w;
		cin>>u>>v>>w;
		if(!flag[u][v]){
			add(u,v,w);
			flag[u][v]=tot;
		}
		else{
			e[flag[u][v]-1].w+=w;
		}
	}
	while(bfs()){
		ans+=dfs(s,INF);
	}
	cout<<ans;
	return 0;
}
The Blog ends

相關文章