网络流学习笔记

我承认了,我粘的 LiveDream Classin里的图!
我没学费用流!

一·网络最大流

1.\(EK\)

这个只是铺垫(

https://oi-wiki.org/graph/flow/max-flow/

2.\(Dinic -> O(n^2m)\)

当多条增广路有很长一部分的公共路径时,\(EK\) 效率不高

如何使一条路只搜一次?

将经过节点 \(x\) 的所有增广路一次搜完

实现:

  • 利用BFS将有向图分层,达到每次走最短路的目的
  • 利用DFS的回溯特点,将一个点 \(x\) 之后的所有增广路全部搜完

我的 \(Dinic:\)

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,m,s,t,head[200005],nxt[200005],edge[200005],to[200005],pre[100005],level[100005];
int tot;
void add(int u,int v,int w){
	to[++tot]=v;
	edge[tot]=w;
	nxt[tot]=head[u];
	head[u]=tot;
	to[++tot]=u;
	edge[tot]=0;
	nxt[tot]=head[v];
	head[v]=tot;
}
bool bfs(){
	memset(level,0,sizeof(level));
	queue<int>q;
	level[s]=1;
	q.push(s);
	while(!q.empty()){
		int cur=q.front();
		q.pop();
		for(int i=head[cur];i;i=nxt[i]){
			if(edge[i]&&!level[to[i]]){
				q.push(to[i]);
				level[to[i]]=level[cur]+1;
				if(to[i]==t)return 1;
			}
		}
	}
	return 0;
}
int Dinic(int x,int flow){
	if(x==t)return flow;
	int rest=flow,increase;
	for(int i=head[x];i&&rest;i=nxt[i]){
		int y=to[i];
		if(edge[i]&&level[y]==level[x]+1){
			increase=Dinic(y,min(rest,edge[i]));
			if(!increase)level[y]=0;
			edge[i]-=increase;
			edge[i^1]+=increase;
			rest-=increase;
		}
	}
	return flow-rest;
}
signed main(){
	ios::sync_with_stdio(0);
	cin>>n>>m>>s>>t;
	cin.tie(0);
	cout.tie(0);
	tot=1;
	for(int i=1;i<=m;++i){
		int u,v,w;
		cin>>u>>v>>w;
		add(u,v,w);
	}
	int flow=0,maxflow=0;
	while(bfs())maxflow+=Dinic(s,1000000000);
	cout<<maxflow;
	return 0;
}

最大流中的最小割问题:

使得原点 \(s\) 与 汇点 \(t\) 不连通至少需要删除的边权和。

结论:最小割=最大流(割的和上限边是同一个边)

最大权闭合子图问题

什么是闭合子图?

在有向图G(V,E)中,存在子图G'(V',E'),使得V'中的点
沿着E'到达的顶点x也是V'中的点,那么G'就是G的闭合子图。

什么是最大权闭合子图?

权值在点上,所有闭合子图中,点权和最大的闭合子图

问题雏形

给定 n 种物品,均有价格,m 个组合对应 m 种收益(可重叠,价格只算一次,收益重叠),求最大收益。

建模方法

\(ProblesSet\)

  • \(P2057\)
posted @ 2023-01-12 15:13  Forever1507  阅读(8)  评论(0编辑  收藏  举报