YbtOJ「图论」第3章 网络流模型及应用 A. 【例题1】任务分配 题解--zhengjun

思路

这道题网络流建模十分妙妙。

首先从源点 \(s\) 连一条流量为 \(a_i\) 的边到 \(i\),从 \(i\) 连一条流量为 \(b_i\) 的边到汇点 \(t\)

把答案当做这张图的最小割,如果加了一条限制 \((x,y,v)\),那么也就是如果割掉了两个点同侧的边就不用其他费用,否则要加上费用。

发现要加上费用的情况时,相当于我们要再加上一条边,使得如果选择割这两个点异侧的边,那么就还需要再割掉一条边才行。

所以我们在 \(x\)\(y\) 之间连一条流量为 \(v\) 的双向边,这样就可以很好地符合我们的要求。

最后求出最大流(数值上等于最小割)。

代码

#include<bits/stdc++.h>
using namespace std;typedef long long ll;const int N=5e3+10,M=(N*2+2e4)*2;const ll inf=1e18;
int n,m,s,t,head[N],kk=1,cur[N],d[N];struct edges{int to;ll c;int nex;}edge[M];
void add(int u,int v,int c1,int c2){edge[++kk]={v,c1,head[u]};head[u]=kk;edge[++kk]={u,c2,head[v]};head[v]=kk;}
bool bfs(){
	queue<int>q;q.push(s);memset(d,-1,sizeof d);d[s]=0;cur[s]=head[s];for(int u;!q.empty();q.pop()){
		u=q.front();for(int i=head[u],v;v=edge[i].to,i;i=edge[i].nex)
			if(!~d[v]&&edge[i].c)q.push(v),d[v]=d[u]+1,cur[v]=head[v];
	}return ~d[t];
}
ll dfs(int u,ll lim=inf){
	if(u==t)return lim;ll flow=0;for(int i=cur[u],v;v=edge[i].to,i&&flow<lim;i=edge[i].nex){
		cur[u]=i;if(d[v]!=d[u]+1||!edge[i].c)continue;ll f=dfs(v,min(lim-flow,edge[i].c));
		if(!f)d[v]=-1;edge[i].c-=f;edge[i^1].c+=f;flow+=f;
	}return flow;
}
ll dinic(){ll maxflow=0;while(bfs())maxflow+=dfs(s);return maxflow;}
int main(){
	scanf("%d%d",&n,&m);s=0;t=n+1;for(int i=1,a,b;i<=n;i++)scanf("%d%d",&a,&b),add(s,i,a,0),add(i,t,b,0);
	for(int i=1,u,v,w;i<=m;i++)scanf("%d%d%d",&u,&v,&w),add(u,v,w,w);cout<<dinic();return 0;
}
posted @ 2022-07-01 14:44  A_zjzj  阅读(26)  评论(0编辑  收藏  举报