2022/1/19

2022/1/19

网络流练习&&模板

[P3376 【模板】网络最大流]( P3376 [模板]网络最大流 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) )

参考代码

#include<bits/stdc++.h>
#define ll  long long
#define pii pair<long long , long long >
#define se second
#define pb push_back
#define pf push_front
#define si size()
#define db double
#define ls (p<<1)
#define rs (p<<1|1)
#define fi first
#define se second
#define watch(x) std::cout << (#x) << " is " << (x) << std::endl

using namespace std;
ll read(){ll x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;}
inline void Prin(ll x){if(x < 0){putchar('-');x = -x;}if(x > 9) Prin(x / 10);putchar(x % 10 + '0');}

const int qs=8192*2;
const ll mod=998244353;
const ll inf=0x3f3f3f3f3f3f3f3f;

ll n,m,s,t;

ll head[qs],nxt[qs],to[qs];
ll dis[qs]; 
ll p;

void add(int fx,int tx,ll dx){
	to[p]=tx;
	dis[p]=dx;
	nxt[p]=head[fx];
	head[fx]=p++;
}

//Dinic
ll level[qs],cur[qs];
//level是各点到终点的深度,cur为当前弧优化的增广起点 

bool bfs(){//分层图 
	memset(level,-1,sizeof(level));
	level[s]=0;
	memcpy(cur,head,sizeof(head));
	cur[s]=head[s];
	queue<int> Q;
	Q.push(s);
	while(Q.si){
		int k=Q.front();
		Q.pop();
		for(int i=head[k];i!=-1;i=nxt[i]){
			if(dis[i]>0&&level[to[i]]==-1){
				level[to[i]]=level[k]+1;
				Q.push(to[i]);
				if(to[i]==t) return true;
			}
		}
	}
	return false;
}

ll dfs(int u,ll flow){
	if(u==t) return flow;
	
	ll ret=flow; //剩余的流量
	for(int i=cur[u];i!=-1&&ret>0;i=nxt[i]){
		cur[u]=i;// 当前弧优化
		//如果还能流下去 并且 更深 
		if(dis[i]>0&&level[to[i]]==level[u]+1){
			ll c=dfs(to[i],min(dis[i],ret));
			if(!c) level[to[i]]=-1; //剪枝,出去增广完毕的点 
			ret-=c; //剩余的水流被用了c
			dis[i]-=c;	//减权重 
			dis[i^1]+=c; //反向边加权重 
		}
	} 
	return flow-ret;//返回用掉的水流 
}

//END 

int main(){
	memset(head,-1,sizeof(head));
	cin>>n>>m>>s>>t;
	ll x,y,z;
	while(m--){
	
		cin>>x>>y>>z;
		add(x,y,z);
		add(y,x,0);// 反向边
		//第一条边的序号是0,反向边是1 
	}
	ll ans=0;
	while(bfs()){
		ans+=dfs(s,inf);
	}
	cout<<ans<<"\n";
	return 0;
}

[ Dining ]( Dining (nowcoder.com) )

思路

考虑网络流(源点-食物-牛-饮料-汇点)建模,要保证一个牛只吃一种食物和一种饮料,

  1. 从源点s向食物做流量为1的边。
  2. 根据牛想吃的食物,从食物向牛连一条流量为1的边
  3. 从牛向饮料连一条流量为1的边
  4. 从饮料向汇点连一条流量为1的边

这样建出来的图不能保证一个牛只吃一种食物和饮料,因为增光路保证边不重复,但点可以经过多次,故还要牛向本身连一条流量为1的边。

参考代码

#include<bits/stdc++.h>
#define ll  long long
#define pii pair<long long , long long >
#define se second
#define pb push_back
#define pf push_front
#define si size()
#define db double
#define ls (p<<1)
#define rs (p<<1|1)
#define fi first
#define se second
#define watch(x) std::cout << (#x) << " is " << (x) << std::endl

using namespace std;
ll read(){ll x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;}
inline void Prin(ll x){if(x < 0){putchar('-');x = -x;}if(x > 9) Prin(x / 10);putchar(x % 10 + '0');}

const int qs=8192*2;
const ll mod=998244353;
const ll inf=0x3f3f3f3f3f3f3f3f;

ll N,F,D,s,t;

ll head[qs],nxt[qs],to[qs];
ll dis[qs]; 
ll p;
map<int,bool> mp;

void add(int fx,int tx,ll dx){
	to[p]=tx;
	dis[p]=dx;
	nxt[p]=head[fx];
	head[fx]=p++;
	
	to[p]=fx;
	dis[p]=0;
	nxt[p]=head[tx];
	head[tx]=p++;
}

//Dinic
ll level[qs],cur[qs];
//level是各点到终点的深度,cur为当前弧优化的增广起点 

bool bfs(){//分层图 
	memset(level,-1,sizeof(level));
	level[s]=0;
	memcpy(cur,head,sizeof(head));
	cur[s]=head[s];
	queue<int> Q;
	Q.push(s);
	while(Q.si){
		int k=Q.front();
		Q.pop();
		for(int i=head[k];i!=-1;i=nxt[i]){
			if(dis[i]>0&&level[to[i]]==-1){
				level[to[i]]=level[k]+1;
				Q.push(to[i]);
				if(to[i]==t) return true;
			}
		}
	}
	return false;
}

ll dfs(int u,ll flow){
	if(u==t) return flow;
	
	ll ret=flow; //剩余的流量
	for(int i=cur[u];i!=-1&&ret>0;i=nxt[i]){
		cur[u]=i;// 当前弧优化
		//如果还能流下去 并且 更深 
		if(dis[i]>0&&level[to[i]]==level[u]+1){
			ll c=dfs(to[i],min(dis[i],ret));
			if(!c) level[to[i]]=-1; //剪枝,出去增广完毕的点 
			ret-=c; //剩余的水流被用了c
			dis[i]-=c;	//减权重 
			dis[i^1]+=c; //反向边加权重 
		}
	} 
	return flow-ret;//返回用掉的水流 
}

//END 

int main(){
	memset(head,-1,sizeof(head));
	N=read(),F=read(),D=read();
	s=0,t=N+F*2+D+1;
	for(int i=1;i<=F;++i) add(s,i,1);	
	for(int i=1;i<=N;++i) add(F+i,N+F+i,1);
	for(int i=1;i<=D;++i) add(F+N*2+i,t,1);
	ll Fi,Di,x;
	for(int Ni=1;Ni<=N;++Ni){
		Fi=read(),Di=read();
		for(int i=1;i<=Fi;++i){
			x=read();
			add(x,F+Ni,1);
		}
		for(int i=1;i<=Di;++i){
			x=read();
			add(N+F+Ni,x+F+N*2,1);
		}
	}
	ll ans=0;
	while(bfs()){
		ans+=dfs(s,inf);
	}
	cout<<ans<<"\n";
	return 0;
}


/*

*/


posted @ 2022-01-20 00:20  Suki_Sugar  阅读(21)  评论(0编辑  收藏  举报
Live2D