网络流总结

本文分享了作者学习网络流算法两个月的心得,详细介绍了经典题目如草地排水、最长递增子序列等问题的解决方法,并提供了完整的代码实现。文章还探讨了费用流在不同场景中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

学网络流也有两个月了吧,要发一下代码了吧。

说实话反向边那些东西十分简单,理解了就好

费用流也就是一个SPFA加一句话,水爆了

最烦连边了,连完了打板子,啥都不想

例题:

POJ1273 草地排水

板子题,看板子过

奇丑无比的FF加上强迫症的代码风格:

#include<cstdio>
#include<algorithm>
#include<cstring>
#define inf 99999999
using namespace std;
const int maxn=205,maxm=maxn<<1;
int fir[maxn],nxt[maxm],w[maxm],dis[maxm];
int n,m;
inline int gi();
inline void adde(int a,int b,int W,int id){nxt[id]=fir[a],fir[a]=id,dis[id]=b,w[id]=W;}
inline int rev(int id){if(id&1)return id+1;else return id-1;}
void init();void work();int dfs(int,int,int);
int main(){while(scanf("%d%d",&m,&n)==2)init(),work();return 0;}
void init(){
	memset(fir,0,sizeof(fir));
	int a,b,c;
	for(int i=1;i<=m;i++)
		a=gi(),b=gi(),c=gi(),adde(a,b,c,(i<<1)-1),adde(b,a,0,i<<1);
}
bool vis[maxn];
void work(){
	int ans=0,D=1;
	while(D){
		memset(vis,0,sizeof(vis));
		D=dfs(1,n,inf),ans+=D;
	}
	printf("%d\n",ans);
}
int dfs(int now,int end,int minn){
	if(now==end)return minn;
	vis[now]=1;
	for(int i=fir[now];i;i=nxt[i]){
		if(!vis[dis[i]]&&w[i]>0){
			register int down=dfs(dis[i],end,min(minn,w[i]));
			if(down){
				w[i]-=down,w[rev(i)]+=down;
				return down;
			}
		}
	}
	return 0;
}
int gi() {
	int x=0;
	char ch=getchar();
	while(ch<'0'||ch>'9')ch=getchar();
	while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
	return x;
}

【网络流24题】最长递增子序列

板子题,DP之后连边比较奇特(实力还弱啊QAQ)

奇丑无比的inf都不define的无聊代码(最讨厌这种几问的题):

#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
#define t (dis[i])
using namespace std;
inline int gi() {
	int x=0,f=1;
	char ch=getchar();
	while(ch>'9'||ch<'0')f=(ch=='-')?-1:f,ch=getchar();
	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
	return x*f;
}
inline void Dp();
inline void solve(int);
int X[501],F[501];
int n,K,S,T;
int main() {
	n=gi();
	for(int i=1; i<=n; i++)X[i]=gi();
	Dp();
	S=n+1,T=n+2,solve(1),solve(1000);
	return 0;
}
const int maxn=521,maxm=400001<<1;
int fir[maxn],dis[maxm],w[maxm],nxt[maxm],dep[maxn];
inline void Dp() {
	int ans=0;
	for(int i=1; i<=n; i++) {
		F[i]=1;
		for(int j=1; j<i; j++)if(X[j]<=X[i])F[i]=max(F[i],F[j]+1);
		ans=max(F[i],ans);
	}
	printf("%d\n",K=ans);
}
int Index=1;
inline void adde(int a,int b,int ww) {
	nxt[++Index]=fir[a],fir[a]=Index,dis[Index]=b,w[Index]=ww;
	if(ww)adde(b,a,0);
}
inline bool BFS() {
	queue<int>bfs;
	memset(dep,0,sizeof dep);
	bfs.push(S);
	bool yes[600]= {0};
	yes[S]=1,dep[S]=0;
	while(!bfs.empty()) {
		int now=bfs.front();
		for(int i=fir[now]; i; i=nxt[i])
			if(w[i]>0&&!yes[t])
				yes[t]=1,bfs.push(t),dep[t]=dep[now]+1;
		bfs.pop();
	}
	return yes[T];
}
inline int Dinic(int now,int h) {
	if(now==T)return h;
	int ans=0;
	for(int i=fir[now]; i; i=nxt[i])
		if(w[i]>0&&dep[t]==dep[now]+1) {
			int D=Dinic(t,min(h,w[i]));
			w[i]-=D,w[i^1]+=D,ans+=D,h-=D;
			if(h==0)return ans;
		}
	return ans;
}
inline void solve(int hehe) {
	memset(fir,0,sizeof fir);
	Index=1;
	for(int i=1; i<n; i++)
		for(int j=i+1; j<=n; j++)
			if(X[i]<=X[j]&&F[i]+1==F[j])adde(i,j,1);
	if(hehe^1) {
		adde(S,1,hehe);
		for(int i=2; i<=n; i++)if(F[i]==1)adde(S,i,1);
		for(int i=1; i<n; i++)if(F[i]==K)adde(i,T,1);
		if(F[n]==K)adde(n,T,hehe);
	} else {
		for(int i=1; i<=n; i++)if(F[i]==1)adde(S,i,1);
		for(int i=1; i<=n; i++)if(F[i]==K)adde(i,T,1);
	}
	int ans=0;
	while(BFS())ans+=Dinic(S,10000000);
	printf("%d\n",ans);
}
【网络流24题】数字梯形(费用流):
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
#define inf 10000000
#define up +0
#define down +1
#define t (dis[i])
const int maxn=1001<<1,maxm=10000<<1,S=2000,T=2001;
using namespace std;
int fir[maxn],dis[maxm],w[maxm],cost[maxm],nxt[maxm],id=1,m,n;
int INDEX=0;
inline void add(int a,int b,int c,int d,int e=0){
  nxt[++id]=fir[a],fir[a]=id,dis[id]=b,w[id]=c,cost[id]=d;
  if(c)add(b,a,0,e);
}
int num[21][41],Index[21][41];
inline void build(int a,int b){
  memset(fir,0,sizeof fir);
  for(int i=1;i<=m;i++)add(S,Index[1][i]up,1,0);
  for(int i=1;i<=m+n-1;i++)add(Index[n][i]down,T,a,0);
  for(int i=1;i<n;i++)
    for(int j=1;j<m+i;j++){
      add(Index[i][j]up,Index[i][j]down,a,-num[i][j],num[i][j]);
      add(Index[i][j]down,Index[i+1][j]up,b,0);
      add(Index[i][j]down,Index[i+1][j+1]up,b,0);
    }
  for(int j=1;j<m+n;j++)
      add(Index[n][j]up,Index[n][j]down,a,-num[n][j],num[n][j]);
}
int que[maxn],vis[maxn],pre[maxn],Dis[maxn];
inline bool spfa(){
  int hd=1,tl=1;
  for(int i=1;i<=INDEX;i++)Dis[i]=inf;
  memset(vis,0,sizeof vis);
  Dis[T]=inf,Dis[S]=0,que[tl++]=S,vis[S]=1;
  while(hd^tl){
    int now=que[hd];
    for(int i=fir[now];i;i=nxt[i])
      if(w[i]>0&&Dis[t]>Dis[now]+cost[i]){
	Dis[t]=Dis[now]+cost[i],pre[t]=i;
	if(!vis[t])vis[t]=1,que[tl]=t,tl=(tl+1)%maxn;
      }
    vis[now]=0,hd=(hd+1)%maxn;
  }
  return Dis[T]!=inf;
}
inline int end(int&flow,int sum=inf,int ret=0){
  for(int now=T,p;now^S;now=dis[p^1])p=pre[now],sum=min(sum,w[p]);
  for(int now=T,p;now^S;now=dis[p^1])p=pre[now],w[p]-=sum,w[p^1]+=sum,ret+=cost[p];
  flow+=sum;return ret*sum;
}
inline int maxflow(int ans=0,int flow=0){
  while(spfa())ans+=end(flow);
  return -ans;
}
int main(){
  scanf("%d%d",&m,&n);
  for(int i=0;i<n;i++)
    for(int j=1;j<=m+i;j++)
      scanf("%d",&num[i+1][j]),Index[i+1][j]=++INDEX,++INDEX;
  build(1,1),printf("%d\n",maxflow());
  build(inf,1),printf("%d\n",maxflow());
  build(inf,inf),printf("%d\n",maxflow());
  return 0;
}

【网络流24题】运输问题(费用流):

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#define rg register
#define t (dis[i])
using namespace std;
const int maxd=230,S=maxd-2,T=maxd-1,maxm=maxd*maxd<<1,inf=1000000000;
int m,n,a[101],b[101];
inline int gi() {
	rg int x=0;
	rg char ch=getchar();
	while(ch>'9'||ch<'0')ch=getchar();
	while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
	return x;
}
int fir[maxd],nxt[maxm],dis[maxm],cost[maxm],w[maxm],id=1;
inline void add(int a,int b,int c,int d){
	nxt[++id]=fir[a],fir[a]=id,dis[id]=b,w[id]=c,cost[id]=d;
	if(c)add(b,a,0,-d);
}
inline bool spfa(int&FLOW,int&COST){
	int hd=1,tl=1,que[maxd],inque[maxd]={0},pre[maxd],Dis[maxd];
	que[tl++]=S,inque[S]=1;
	for(int i=1;i<=m+n;i++)Dis[i]=inf;Dis[T]=inf,Dis[S]=0;
	while(hd^tl){
		int now=que[hd];
		for(int i=fir[now];i;i=nxt[i])
			if(w[i]>0&&Dis[t]>Dis[now]+cost[i]){
				Dis[t]=Dis[now]+cost[i],pre[t]=i;
				if(!inque[t])inque[t]=1,que[tl++]=t,tl%=maxd;
			}
		hd=(hd+1)%maxd,inque[now]=0;
	}
	if(Dis[T]==inf)return 0;
	int flow=inf;
	for(int now=T,p;now^S;now=dis[p^1])p=pre[now],flow=min(flow,w[p]);
	for(int now=T,p;now^S;now=dis[p^1])p=pre[now],w[p]-=flow,w[p^1]+=flow,COST+=flow*cost[p];
	FLOW+=flow;	return 1;
}
inline int mincost(int Flow=0,int Cost=0){
	while(spfa(Flow,Cost));return Cost;
}
int main(){
	m=gi(),n=gi();
	for(rg int i=1;i<=m;i++)a[i]=i,add(S,a[i],gi(),0);
	for(rg int i=1;i<=n;i++)b[i]=i+m,add(b[i],T,gi(),0);
	for(rg int i=1;i<=m;i++)for(int j=1;j<=n;j++)add(a[i],b[j],inf,gi());
	printf("%d\n",mincost());
	for(rg int i=2;i<=id;i+=2)w[i]+=w[i^1],w[i^1]=0,cost[i]=-cost[i],cost[i^1]=-cost[i^1];
	printf("%d\n",-mincost());
	return 0;
}

【中学高级本-网络流24题】餐巾计划(较难,看了题解,但还是费用流):

#include<cstdio>
#include<algorithm>
#define X(o) ((o)<<1)
#define Y(o) ((o)<<1|1)
#define t (dis[i])
#define rg register
using namespace std;
int n,r[222],P,fast,slow,fastc,slowc;
const int maxd=420,maxm=23333,S=410,T=411,inf=233333333;
inline int gi() {
	rg int x=0;
	rg char ch=getchar();
	while(ch>'9'||ch<'0')ch=getchar();
	while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
	return x;
}
int fir[maxd],nxt[maxm],dis[maxm],w[maxm],cost[maxm],id=1;
inline void add(int a,int b,int c,int d){
	nxt[++id]=fir[a],fir[a]=id,dis[id]=b,w[id]=c,cost[id]=d;
	if(c)add(b,a,0,-d);
}
inline void build(){
	for(rg int i=1;i<=n;i++){
		add(S,X(i),r[i],0),add(S,Y(i),inf,P);
		add(Y(i),T,r[i],0);
		add(X(i),X(i+1),inf,0);
		if(i+fast<=n)add(X(i),Y(i+fast),inf,fastc);
		if(i+slow<=n)add(X(i),Y(i+slow),inf,slowc);
	}
}
inline bool spfa(int&F,int&C){
	int que[maxd],pre[maxd],Dis[maxd];bool inque[maxd]={0};
	rg int hd=1,tl=1;
	que[tl++]=S,inque[S]=1;
	for(rg int i=1;i<=Y(n);i++)Dis[i]=inf;Dis[T]=inf,Dis[S]=0;
	while(hd^tl){
		rg int now=que[hd];
		for(rg int i=fir[now];i;i=nxt[i])
			if(w[i]>0&&Dis[t]>Dis[now]+cost[i]){
				Dis[t]=Dis[now]+cost[i],pre[t]=i;
				if(!inque[t])que[tl++]=t,tl%=maxd,inque[t]=1;
			}
		hd=(hd+1)%maxd,inque[now]=0;
	}
	if(Dis[T]==inf)return 0;
	rg int sum=inf;
	for(int now=T,p;now^S;now=dis[p^1])p=pre[now],sum=min(sum,w[p]);
	for(int now=T,p;now^S;now=dis[p^1])p=pre[now],w[p]-=sum,w[p^1]+=sum,C+=cost[p]*sum;
	F+=sum;
	return 1;
}
inline int mincost(int Flow=0,int Cost=0){
	while(spfa(Flow,Cost));return Cost;
}
int main(){
	n=gi();
	for(rg int i=1;i<=n;i++)r[i]=gi();
	P=gi(),fast=gi(),fastc=gi(),slow=gi(),slowc=gi();
	build();
	printf("%d\n",mincost());
	return 0;
}

只学了最大流和费用流,比较蒟蒻,什么什么割的什么流还没学(貌似叫最小割最大流吧)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值