网络流、费用流、二分图学习笔记

未完待续

网络流

%%%%强推%%%%

这篇思路不错:https://www.cnblogs.com/ZJUT-jiangnan/p/3632525.html

洛谷日报也还行:https://www.luogu.com.cn/blog/ONE-PIECE/wang-lao-liu-di-zong-jie

这篇dinic强力推荐:https://www.cnblogs.com/DavidJing/p/10713197.html

现在终于知道为什么这么多人用“memset(head,-1)”了

这样tot初始值为-1,第一条边的编号就为0了,用“^i”就可以求出“i”的反向边了

代码:

#include<bits/stdc++.h>
#define ll long long
#define N 110000
using namespace std;
ll n,m,s,t,x,y,z,tot=1,head[N],hd[N],dep[N],inf=0x7fffffff;
struct node{
	ll to,dis,nxt;
}e[5*N];
void add(ll f,ll to,ll dis){
	e[++tot].to=to;
	e[tot].dis=dis;
	e[tot].nxt=head[f];
	head[f]=tot;
}
ll bfs(){
	memcpy(hd,head,sizeof(hd));
	memset(dep,0,sizeof(dep));
	queue<ll>q;
	dep[s]=1;
	q.push(s);
	while(!q.empty()){
		ll u=q.front();
		q.pop();
		for(ll i=head[u];i;i=e[i].nxt){
			ll v=e[i].to;
			if(!dep[v]&&e[i].dis>0){
				dep[v]=dep[u]+1;
				q.push(v);
			}
		}
	}
	return dep[t];
}
ll dfs(ll u,ll lim){
	if(u==t||!lim)return lim;
	ll flow=0;
	for(ll i=hd[u];i&&lim;i=e[i].nxt){
		hd[u]=i;
		ll v=e[i].to,ff;
		if(dep[v]==dep[u]+1&&(ff=dfs(v,min(lim,e[i].dis)))){
			lim-=ff;
			e[i].dis-=ff;
			e[i^1].dis+=ff;
			flow+=ff;
		}
	}
	return flow;
}
ll dinic(){
	ll sum=0;
	while(bfs())sum+=dfs(s,inf);
	return sum;
}
int main(){
	scanf("%lld%lld%lld%lld",&n,&m,&s,&t);
	for(ll i=1;i<=m;i++){
		scanf("%lld%lld%lld",&x,&y,&z);
		add(x,y,z);
		add(y,x,0);
	}
	printf("%lld",dinic());
}

二分图

这篇匈牙利强力推荐:https://blog.csdn.net/u013384984/article/details/90718287

其实二分图匹配还可以用网络流dinic实现

设置一个超级点源S,一个超级点束T

S连向所有左边点,所有右边点连向T,再跑S到T的最大流即可

代码:(匈牙利算法)

#include<bits/stdc++.h>
using namespace std;
const int N=1005;
int n,m,e,u,v,ans,match[N];
bool a[N][N],vis[N];
bool dfs(int x) {
	for(int i=1;i<=m;i++)if(!vis[i]&&a[x][i]){
		vis[i]=1;
		if(!match[i]||dfs(match[i])){
			match[i]=x;
			return 1;
		}
	}
	return 0;
}
int main() {
	scanf("%d %d %d",&n,&m,&e);
	for(int i=1;i<=e;i++)scanf("%d %d",&u,&v),a[u][v]=1;
	for (int i=1; i<=n;i++){
        ans+=dfs(i);
        memset(vis,0,sizeof(vis));
    }
    printf("%d",ans);
}

(dinic)

#include<bits/stdc++.h>
#define ll long long
#define N 110000
using namespace std;
ll n,m,x,y,z,tot=1,s,t,head[N],dep[N],hd[N],inf=0x7fffffff;
struct node{
	ll to,dis,nxt;
}e[5*N];
void add(ll f,ll to,ll dis){
	e[++tot].to=to;
	e[tot].dis=dis;
	e[tot].nxt=head[f];
	head[f]=tot;
}
ll bfs(){
	memcpy(hd,head,sizeof(hd));
	memset(dep,0,sizeof(dep));
	queue<ll>q;
	dep[s]=1;
	q.push(s);
	while(!q.empty()){
		ll u=q.front();
		q.pop();
		for(ll i=head[u];i;i=e[i].nxt){
			ll v=e[i].to;
			if(!dep[v]&&e[i].dis>0){
				dep[v]=dep[u]+1;
				q.push(v);
			}
		}
	}
	return dep[t];
}
ll dfs(ll u,ll lim){
	if(!lim||u==t)return lim;
	ll flow=0;
	for(ll i=hd[u];i&&lim;i=e[i].nxt){
		hd[u]=i;
		ll v=e[i].to,ff=0;
		if(dep[v]==dep[u]+1&&(ff=dfs(v,min(lim,e[i].dis)))){
			lim-=ff;
			e[i].dis-=ff;
			e[i^1].dis+=ff;
			flow+=ff;
		}
	}
	return flow;
}
ll dinic(){
	ll ans=0;
	while(bfs())ans+=dfs(s,inf);
	return ans;
}
int main(){
	scanf("%lld%lld",&n,&m);
	s=m+1,t=m+2;
	while(1){
		scanf("%lld%lld",&x,&y);
		if(x==-1&&y==-1)break;
		add(x,y,inf);
		add(y,x,0);
	}
	for(ll i=1;i<=n;i++){
		add(s,i,1);
		add(i,s,0);
	}
	for(ll i=n+1;i<=m;i++){
		add(i,t,1);
		add(t,i,0);
	}
	ll ans=dinic();
	if(!ans){puts("No Solution!");return 0;}
	printf("%lld\n",ans);
	for(ll i=2;i<=tot;i+=2)if(e[i].to!=s&&e[i].to!=t&&e[i^1].to!=s&&e[i^1].to!=t&&e[i^1].dis!=0){
		printf("%lld %lld\n",e[i^1].to,e[i].to);//然而还可以这样输出匹配结果
	}
}

费用流

把EK里的bfs换成spfa即可

代码:

#include<bits/stdc++.h>
#define ll long long
#define N 110000
using namespace std;
ll n,m,s,t,x,y,z,w,tot=1,mxf,mnc,head[N],hd[N],dis[N],flow[N],pre[N],last[N],inf=0x7fffffff;
bool vis[N];
struct node{
	ll f,to,dis,nxt;
}e[5*N];
void add(ll f,ll to,ll fl,ll dis){
	e[++tot].to=to;
	e[tot].dis=dis;
	e[tot].nxt=head[f];
	e[tot].f=fl;
	head[f]=tot;
}
bool spfa(){
	memset(dis,0x7f,sizeof(dis));
	memset(flow,0x7f,sizeof(flow));
	memset(vis,0,sizeof(vis));
	queue<ll>q;
	vis[s]=1;dis[s]=0;pre[t]=0;
	q.push(s);
	while(!q.empty()){
		ll u=q.front();
		q.pop();
		for(ll i=head[u];i;i=e[i].nxt){
			ll v=e[i].to;
			if(dis[v]>dis[u]+e[i].dis&&e[i].f>0){
				dis[v]=dis[u]+e[i].dis;
				pre[v]=u;
				last[v]=i;
				flow[v]=min(flow[u],e[i].f);
				if(!vis[v]){
					vis[v]=1;
					q.push(v);
				}
			}
		}
		vis[u]=0;
	}
	return pre[t];
}
void dinic(){
	while(spfa()){
		ll u=t;
		mxf+=flow[t];
		mnc+=flow[t]*dis[t];
		while(u!=s){
			e[last[u]].f-=flow[t];
			e[last[u]^1].f+=flow[t];
			u=pre[u];
		}
	}
}
int main(){
	scanf("%lld%lld%lld%lld",&n,&m,&s,&t);
	for(ll i=1;i<=m;i++){
		scanf("%lld%lld%lld%lld",&x,&y,&z,&w);
		add(x,y,z,w),add(y,x,0,-w);
	}
	dinic();
	printf("%lld %lld",mxf,mnc);
}

题单:https://www.cnblogs.com/p-b-p-b/p/10741953.html

posted @ 2020-07-21 19:13  ZTC_ZTC  阅读(156)  评论(0编辑  收藏  举报