我在網上找到的大部分標題為Dinic的費用流感覺都像是EK的費用流,而一些真的Dinic費用流模板中的變量、函數命名又太冗長,不能很直觀地理解。因此我自己寫了一個基於Dinic最大流(后來查了是zkw)的費用流模板,實測比EK費用流快30%-40%,希望有幫助。
#include <bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
// edge
struct Edge{
int from, to, f, w;
}E[1000005];
int Hed[100005], Nex[1000005], ct=1, Cur[100005];
void Add(int a, int b, int f, int w){ //加邊
E[++ct].from=a, E[ct].to=b, E[ct].f=f, E[ct].w=w, Nex[ct]=Hed[a], Hed[a]=ct;
E[++ct].from=b, E[ct].to=a, E[ct].f=0, E[ct].w=-w, Nex[ct]=Hed[b], Hed[b]=ct;
}
// mincostmaxflow
int n, m, s, t, maxflow, mincost, Dis[100005], F[100005];
bool SPFA(){ //最短路分層,從匯點向源點分層能保證DFS走的一定是最短路,不會浪費時間走錯路
queue<int> Q; Q.push(s);
memset(Dis, INF, sizeof Dis);
Dis[s] = 0; int k;
while(!Q.empty()){
k = Q.front(); Q.pop();
F[k] = 0;
for(int i=Hed[k]; i; i=Nex[i]){
if(E[i].f && Dis[k]+E[i].w<Dis[E[i].to]){
Dis[E[i].to] = Dis[k]+E[i].w;
if(!F[E[i].to])
Q.push(E[i].to), F[E[i].to] = 1;
}
}
}
return Dis[t] != INF;
}
int DFS(int k, int flow){
if(k == t){maxflow += flow; return flow;} //達到匯點更新最大流
int sum = 0; F[k] = 1; //F[]保證了當出現 0 費用邊的時候不會出現兩個點之間來回跑的情況
for(int i=Cur[k]; i; i=Nex[i]){
if(!F[E[i].to] && E[i].f && Dis[E[i].to]==Dis[k]+E[i].w){
Cur[k] = i; //當前弧優化
int p = DFS(E[i].to, min(flow-sum, E[i].f));
sum += p, E[i].f -= p, E[i^1].f += p, mincost += p*E[i].w; //更新費用
if(sum == flow) break;
}
}
F[k] = 0;
return sum;
}
void Dinic(){
while(SPFA()){
memcpy(Cur, Hed, sizeof Hed);
DFS(s, INF);
}
}
// main
int main(){
int a, b, c, d;
scanf("%d%d%d%d", &n, &m, &s, &t);
for(int i=1; i<=m; ++i){
scanf("%d%d%d%d", &a, &b, &c, &d);
Add(a, b, c, d);
}
Dinic();
printf("%d %d", maxflow, mincost);
return 0;
}