网络流

(前言:看不懂的代码,听不懂的算法,记记板子就好了,反正遇到也想不出来,也不会打awa)

Dinic求最小割最大流

代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=5010,inf=0x3f3f3f3f;
typedef long long ll;
int n,m,s,t;
int tot=1,to[maxn<<1],nxt[maxn<<1],h[maxn],val[maxn<<1];//tot从1开始便于匹配一对边 
inline void adde(int x,int y,int z){
	to[++tot]=y,nxt[tot]=h[x],val[tot]=z,h[x]=tot;//正向建边 
	to[++tot]=x,nxt[tot]=h[y],val[tot]=0,h[y]=tot;//反向建初始流量为0的反边 

}
int cur[maxn],dis[maxn];
inline int dfs(int u,int rest){
	if(u==t) return rest;//达到汇点 
	int flow=0;//流量 
	for(int i=cur[u],y;i&&rest;i=nxt[i]){
		cur[u]=i;//弧优化 
		y=to[i];
		if(dis[u]+1==dis[y]&&val[i]){
			int k=dfs(y,min(rest,val[i]));
			flow+=k,rest-=k;//流量增加k,剩下的流量减少k 
			val[i]-=k,val[i^1]+=k;//正边限制减小k,反边增加k 
		}
	}
	if(!flow) dis[u]=-1;//去掉增广完毕的点 
	return flow;
}
queue<int>q;
ll dinic(){//bfs
	ll flow=0;
	while(1){
		memcpy(cur,h,sizeof(h));
		memset(dis,-1,sizeof(dis));
		dis[s]=0;
		q.push(s);
		while(!q.empty()){
			int u=q.front();
			q.pop();
			for(int i=h[u];i;i=nxt[i]){
				int y=to[i];
				if(!val[i]) continue;
				if(dis[y]==-1){
					dis[y]=dis[u]+1;
					q.push(y);
				}
			}
		}
		if(dis[t]==-1) return flow;
		flow+=dfs(s,inf);
	}
}
int main(){
	std::ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	cin>>n>>m>>s>>t;
	for(int i=1,a,b,c;i<=m;i++)
	  cin>>a>>b>>c,adde(a,b,c);
	cout<<dinic();
	return 0;
}

Dinic求最小费用最大流

代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=5010,inf=0x3f3f3f3f;
typedef long long ll;
int n,m,s,t,sumcost;
int tot=1,to[maxn<<10],nxt[maxn<<10],h[maxn],val[maxn<<10],cost[maxn<<10];//tot从1开始便于匹配一对边 
inline void adde(int x,int y,int z,int c){
	to[++tot]=y,nxt[tot]=h[x],val[tot]=z,cost[tot]=c,h[x]=tot;
}
inline void addedge(int x,int y,int z,int c){// x到y有一条流量为z费用为c的边 
	adde(x,y,z,c),adde(y,x,0,-c);
}
int cur[maxn],dis[maxn];
bool vis[maxn];
inline int dfs(int u,int rest){
	if(u==t) return rest;//达到汇点 
	int flow=0;//流量 
	vis[u]=1;
	for(int i=cur[u],y;i&&rest;i=nxt[i]){
		cur[u]=i;//弧优化 
		y=to[i];
		if(!vis[y]&&dis[u]+cost[i]==dis[y]&&val[i]){
			int k=dfs(y,min(rest,val[i]));
			if(!k) dis[y]=inf;
			flow+=k,rest-=k;//流量增加k,剩下的流量减少k 
			val[i]-=k,val[i^1]+=k;//正边限制减小k,反边增加k 
			sumcost+=k*cost[i];
		}
	}
	vis[u]=0;
	return flow;
}
queue<int>q;
ll dinic(){//bfs
	ll flow=0;
	while(1){
		memset(vis,0,sizeof(vis));
		memcpy(cur,h,sizeof(h));
		memset(dis,0x3f,sizeof(dis));
		q.push(s);
		vis[s]=1;
		dis[s]=0;
		while(!q.empty()){
			int u=q.front();
			q.pop();
			vis[u]=0;
			for(int i=h[u];i;i=nxt[i]){
				int v=to[i];
				if(val[i]&&dis[v]>dis[u]+cost[i]){
					dis[v]=dis[u]+cost[i];
					if(!vis[v]){
						q.push(v);
						vis[v]=1;
					}
				} 
				
			}
		}
		if(dis[t]==inf) return flow;
		flow+=dfs(s,inf);
	}
}
int main(){
	std::ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	cin>>n>>m;
	s=1,t=n;
	for(int i=1,a,b,c,d;i<=m;i++)
	  cin>>a>>b>>c>>d,addedge(a,b,c,d);
	cout<<dinic()<<" ";
	cout<<sumcost;
	return 0;
}

求最大权闭合子图

1.定义:有向图中每个点都有一个权。一个闭合子图是指这个有向图的一个点集(包括空集),其中该点集中所有点的出边连向的点还是点集中的点。

2.构造:建立源点\(S\) 和汇点\(T\)。将源点向所有正点权的点连边,容量为点权;将所有负点权的点向汇点连边,容量为点权绝对值。(0权值点可以当作正权点或者负权点,无影响。)原图中的边保持不变,容量为\(inf\)

3.引理:原图对应的最大权值闭合子图的权值和等于所有正权点的权值减去最小割。
例题

代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=5e4+10,maxm=1e6+10,inf=0x3f3f3f3f;
int n,m,s,t,sum;
int tot=1,to[maxm<<1],nxt[maxm<<1],h[maxm],val[maxm<<1];
inline void adde(int x,int y,int z){
	to[++tot]=y,nxt[tot]=h[x],val[tot]=z,h[x]=tot;
	to[++tot]=x,nxt[tot]=h[y],val[tot]=0,h[y]=tot;
} 
int dis[maxm],cur[maxm<<1];
inline int dfs(int x,int rest){
	if(x==t) return rest;
	int flow=0;
	for(int i=cur[x];i;i=nxt[i]){
		int y=to[i];
		cur[x]=i;
		if(val[i]&&dis[y]==dis[x]+1){
			int kk=dfs(y,min(val[i],rest));
			rest-=kk,flow+=kk;
			val[i]-=kk,val[i^1]+=kk;
		}
	}
	if(!flow) dis[x]=-1;
	return flow;
}
queue<int> q;
inline int dinic(){
	int flow=0;
	while(1){
		memset(dis,-1,sizeof(dis));
		memcpy(cur,h,sizeof(h));
		dis[s]=0;
		q.push(s);
		while(q.size()){
			int u=q.front();
			q.pop();
			for(int i=h[u];i;i=nxt[i]){
				if(!val[i]) continue;
				int y=to[i];
				if(dis[y]==-1){
					dis[y]=dis[u]+1;
					q.push(y);
				}
			}
		}
		if(dis[t]==-1) return flow;
		flow+=dfs(s,inf);
	}
};
int main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	cin>>n>>m;
	s=0,t=n+m+1;
	for(int i=1,x;i<=n;i++) cin>>x,adde(i,t,x);
	for(int i=n+1,u,v,w;i<=n+m;i++) cin>>u>>v>>w,adde(s,i,w),adde(i,u,inf),adde(i,v,inf),sum+=w;
	cout<<sum-dinic();
	return 0;
}
posted @ 2025-08-09 15:44  _dlwlrma  阅读(7)  评论(0)    收藏  举报