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;
}