To_Heart—总结——最小费用流 dijkstra+EK
前言
因为害怕 SPFA 哪天就死了,所以好好学习天天向上的学习 dijkstra 吧!
最小费用流 dijkstra+EK
因为费用有可能是负数,但我们 可爱 的 d i j k s t r a dijkstra dijkstra 并不能处理负的边权,所以我们需要利用 J o h n s o n Johnson Johnson 算法中的势函数:
我们对于每一个点定义一个势函数 h h h,把每条边权 w i w_i wi 改为 w i + h i − h j w_i+h_i-h_j wi+hi−hj,其中 h i h_i hi 和 h j h_j hj 表示这条边的 起点 和 终点 的势函数。
而且我们考虑从起点 s s s 到 任意点 i i i 的一条路径,如果每条边都这样处理,实际上路径上除了 s s s 和 i i i 之外的其他点的势函数都被抵消了,所以每一条边的相对大小是没有改变的,所以我们找的最短路的路径是不会改变的。且因为路径上的两点势函数抵消了,所以算出来的答案只需要在减去 h t − h s h_t-h_s ht−hs 就行了。
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define int ll
#define fir first
#define sec second
const ll INF=0x3f3f3f3f;
struct zz{
int u,w,f,id;
};
vector<zz> v[200005];
struct EK{
int s,t,MinCost,MaxFlow,len;
int Dist[5005],h[5005],f[5005];
int pre[5005],e[5005];
void Add(int x,int y,int z,int val){
int idx=v[x].size(),idy=v[y].size();
v[x].push_back((zz){y,z,val,idy});
v[y].push_back((zz){x,0,-val,idx});
}
bool Dijkstra(){
memset(f,0,sizeof f);memset(Dist,0x3f,sizeof Dist);
priority_queue<pair<int,int> > q; q.push({0,s});Dist[s]=0;
while(q.size()){
int x=q.top().sec;q.pop(); if(f[x]) continue; f[x]=1;
for(int i=v[x].size()-1;~i;i--){
int y=v[x][i].u,w=v[x][i].w,val=v[x][i].f;
if(w&&Dist[y]>Dist[x]+val+h[x]-h[y]){
Dist[y]=Dist[x]+val+h[x]-h[y];
pre[y]=x,e[y]=i;
if(!f[y]) q.push({-Dist[y],y});
}
}
}
for(int i=0;i<=len;i++) if(Dist[i]<INF) h[i]+=Dist[i];
memset(f,0,sizeof f);
return Dist[t]<INF;
}
int DFS(int x,int sum){
if(x==t||!sum) return sum;
int siz=v[x].size(),ans=0;f[x]=1;
for(int i=0;i<siz&&sum!=ans;i++){
int y=v[x][i].u,w=v[x][i].w,id=v[x][i].id,val=v[x][i].f;
if(!w||f[y]||h[x]+val!=h[y]) continue;
int now=DFS(y,min(sum-ans,w));
v[x][i].w-=now,v[y][id].w+=now,ans+=now,MinCost+=now*val;
}
f[x]=0;
return ans;
}
void dinic(){
int now=0;
while(Dijkstra()) while(now=DFS(s,INF)) MaxFlow+=now;
}
void Ek(){
int T=0;
while(Dijkstra()){
int Min=INF;
for(int y=t,x=pre[t];y!=s;y=pre[y],x=pre[y]) Min=min(Min,v[x][e[y]].w);
for(int y=t,x=pre[t];y!=s;y=pre[y],x=pre[y])
v[x][e[y]].w-=Min,v[y][v[x][e[y]].id].w+=Min;
MinCost+=h[t]*Min,MaxFlow+=Min;
}
}
}T;
int n,m;
signed main(){
cin>>n>>m>>T.s>>T.t;
// T.s=1,T.t=n;
T.len=n;
for(int i=1,x,y,z,val;i<=m;i++) scanf("%lld%lld%lld%lld",&x,&y,&z,&val),T.Add(x,y,z,val);
T.dinic();
printf("%lld %lld\n",T.MaxFlow,T.MinCost);
return 0;
}