这个zkw大神非常6,把两种很显然的网络流算法结合了起来。
zkw费用流=EK费用流+Dinic最大流
对,你没有看错。
我们回忆一下Dinic找增广路的过程,是不是一遇到一条可以走的边就走,走出来一条源点到汇点的一条可行的路径,就可以了。
我们再回忆一下EK费用流的过程,是不是先跑SPFA,使其找出一条流量不为0的,最小费用的,从源点到汇点的,路径。
这条路也是可行的,那么我们每次做SPFA只能增广一条路径。
剩下SPFA剩下的数据就没有用了?
结合一下,我们当前增广的路径肯定在源点的最短路图上。这个结论是不是挺显然的。
因为一条不在最短路图上的路径肯定费用没有最短路图上的费用小。
这个最短路图也是可以一次SPFA跑出来的。(正着跑和反着跑其实都是一个道理)。
这时,我们顺着最短路图来做一次Dinic找增广路就可以了。
并且,我们再做SPFA的时候,顺便分一下层,那就可以很好的利用Dinic的分层优化。
SPFA的SLF优化也可以加上。
优点大于缺点:在数据量较大的时候,特别是增广路较多,较长的时候,特别有优势。
缺点不说了吧,就是数据小的时候常数大。这个是无法避免的。
#include
#include
#include
#include
#include
using namespace std;
int n,m,begin,end;
struct edge{
int x,y,next,c,cos;
}s[100010];
int first[5010],len=1;
deque f;
bool tf[5010];
int d[5010],ty[5010];
void ins(int x,int y,int c,int cos){
len++;s[len]=(edge){x,y,first[x],c,cos};first[x]=len;
len++;s[len]=(edge){y,x,first[y],0,-cos};first[y]=len;
}
bool SPFA(){
memset(tf,false,sizeof(tf));
memset(ty,0,sizeof(ty));
memset(d,63,sizeof(d));d[begin]=0;ty[begin]=1;
f.push_back(begin);tf[begin]=true;
while(!f.empty()){
int x=f.front();f.pop_front();tf[x]=false;
for(int i=first[x];i!=0;i=s[i].next){
int y=s[i].y;
if(d[y]>d[x]+s[i].cos && s[i].c>0){
d[y]=d[x]+s[i].cos;
ty[y]=ty[x]+1;
if(!tf[y]){
tf[y]=true;
if(!f.empty() && d[y]0){
tot+=(my=dfs(y,min(t-tot,s[i].c),flow,cost));
cost+=my*s[i].cos;
s[i].c-=my;s[i^1].c+=my;
}
}
return tot;
}
void MCMF(){
int flow=0,cost=0;
while(SPFA()){
we=true;
while(we) we=false,dfs(begin,1e9,flow,cost);
}
printf("%d %d\n",flow,cost);
}
int main(){
scanf("%d %d %d %d",&n,&m,&begin,&end);
int x,y,c,cos;
for(int i=1;i<=m;i++){
scanf("%d %d %d %d",&x,&y,&c,&cos);
ins(x,y,c,cos);
}
MCMF();
}