费用流
理解
在lzz大佬讲解下一下就理解了,%%%
就是把bfs改称spfa,中间的dis数组就是费用,也就是要找到s到t的最短路作为增光路
所以所有在dinic找到的增光路费用都是相同的,然后就是板子了
注意在dinic中,防止有负环,所以要用vis数组像dfs一样进行判重
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=5e3,M=5e4+5,inf=1e14;
int n,m,cnt=1,ans1,ans2,cost;
int dis[N],vis[N],head[N],s[N],now[N];
struct edge{
int v,w,c,nxt;
}e[M*2];
void add(int u,int v,int c,int w){
e[++cnt]={v,w,c,head[u]};
head[u]=cnt;
}
bool SPFA(){
for(int i=1;i<=n;i++) dis[i]=inf,vis[i]=0,now[i]=head[i],s[i]=0;
queue<int>q;
dis[1]=0;
q.push(1);
s[1]=1;
while(!q.empty()){
int u=q.front();
q.pop();
s[u]=0;
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].v,w=e[i].w,c=e[i].c;
if(c&&dis[v]>dis[u]+w){
dis[v]=dis[u]+w;
q.push(v),s[v]=1;
}
}
}
cost=dis[n];
if(dis[n]<inf) return 1;
return 0;
}
int dinic(int u,int sum){
if(u==n) return sum;
vis[u]=1;
int flow=0;
for(int i=now[u];i&∑i=e[i].nxt){
now[u]=i;//写成i了
int v=e[i].v,c=e[i].c,w=e[i].w;
if(c&&dis[v]==dis[u]+w&&!vis[v]){
int k=dinic(v,min(sum,c));
if(!k) dis[v]=inf;
e[i].c-=k,e[i^1].c+=k;//+-别写反了!!!!!!!!
flow+=k,sum-=k;
}
}
vis[u]=0;
return flow;
}
signed main(){
scanf("%lld%lld",&n,&m);
for(int i=1;i<=m;i++){//别写成n了!!!!!!!!!!!!!!!
int u,v,w,c;
scanf("%lld%lld%lld%lld",&u,&v,&c,&w);
add(u,v,c,w),add(v,u,0,-w);
}
while(SPFA()){
int flow=dinic(1,inf);
ans1+=flow;
ans2+=flow*cost;
}
printf("%lld %lld\n",ans1,ans2);
}

浙公网安备 33010602011771号