Zkw费用流

V#include 
using namespace std;
bool vis[200001];int dist[200001];//vis是spfa访问标记及増广访问标记,dist是每个点距离标号
int n,m,s,t,ans=0;//s是起点,t是终点,ans是费用答案
int nedge=-1,p[200001],c[200001],cc[200001],nex[200001],head[200001];//nedge为边编号
//p,c,cc,nex表编号为i的边终点,流量,费用,下一条边,head表编号为i的点射出的最后一边
void addedge(int x,int y,int z,int zz){
    p[++nedge]=y;c[nedge]=z;cc[nedge]=zz;nex[nedge]=head[x];head[x]=nedge;
}   //建边(数组模拟边表倒挂)
bool spfa(int s,int t){
    memset(vis,0,sizeof vis);       //深搜前先清0
    for(int i=0;i<=n;i++)dist[i]=1e9;
    dist[t]=0;vis[t]=1;            //SPFA维护距离标号要倒着跑,维护出到终点的最短路径
    dequeq;q.push_back(t);  //使用了SPFA的队列优化
    while(!q.empty()){
        int now=q.front();q.pop_front();
        for(int k=head[now];k>-1;k=nex[k]){		 //下一行的k^1可保证正流
            if(c[k^1]&&dist[p[k]]>dist[now]-cc[k]){  //SPFA倒着跑故c[k]对应反向边是为正
                dist[p[k]]=dist[now]-cc[k];//已经倒着,建边时反向边权为负,故负负得正
                if(!vis[p[k]]){
                    vis[p[k]]=1;
                    if(!q.empty()&&dist[p[k]]-1;k=nex[k])
        if(!vis[p[k]]&&c[k]&&dist[x]-cc[k]==dist[p[k]]){//未访问,有流量,此边在最短路径上
            a=dfs(p[k],min(c[k],low-used));             //往下一个点深搜且流量降低
            if(a)ans+=a*cc[k],c[k]-=a,c[k^1]+=a,used+=a;//深搜有流:加钱,减流,加流,递归流
            if(used==low)break;                   //流量流完了可以退出(本题可忽略)
    }                                          //这题最大流不定,故开了1E9无限大
    return used;
}



int costflow(){				   //开始跑
    int flow=0;					   //开始时流量为0
    while(spfa(s,t)){                  //判断起点终点是否连通,不连通则满流退出
        vis[t]=1;                    //只是为了第一次可以进入vis
        while(vis[t]){
            memset(vis,0,sizeof vis);	  //先清零,看下面的深搜能否更新到终点
            flow+=dfs(s,1e9);        //一直増广直到走不到为止
        }
    }
    return flow;                     //返回最大流,费用在ans里
}
int main(){
    memset(nex,-1,sizeof nex);memset(head,-1,sizeof head);//初始化nex与head数组
    scanf("%d%d%d%d",&n,&m,&s,&t);              //输入点数,边数,起点,终点
    for(int i=1;i<=m;i++){                          //逐条边输入
        int x,y,z,zz;scanf("%d%d%d%d",&x,&y,&z,&zz); //起点,终点,可流量,花费
        addedge(x,y,z,zz);addedge(y,x,0,-zz);
    }
    printf("%d ",costflow());printf("%d",ans);         //输入最大流时流量与费用
    return 0;
}
Zkw费用流
洛谷3381最小费用最大流
题目描述
如题,给出一个网络图,以及其源点和汇点,每条边已知其最大流量和单位流量费用,求出其网络最大流和在最大流情况下的最小费用。
输入第一行四个正整数N、M、S、T,表示点的个数、有向边的个数、源点序号、汇点序号。接下来M行每行包含四个正整数ui、vi、wi、fi,表示第i条有向边从ui出发,到达vi,边权为wi(即该边最大流量为wi),单位流量的费用为fi。
输出最大流量和在最大流量情况下的最小费用。
输入: 		输出:
4 5 4 3		50 280
4 2 30 2
4 3 20 3
2 3 20 1
2 1 30 9
1 3 40 5
zkw费用流的优缺点:
原版优势:节省了大量的跑SPFA的时间,还有多路増广的大优势,这个特点可以在许多路径都费用相同的时候派上用场, 进一步减少了重标号的时间耗费
zkw优势:SPFA多路増广版本多跑了SPFA,多路増广的优势犹存,所以时间上还是蛮优秀的,再加上SLF优化之后减小的常数也是很高效的
zkw劣势:对于流量不大, 费用不小, 增广路还较长的网络,zkw体现出来的优势并不大,甚至可能比普通EK慢

 

你可能感兴趣的:(ACM笔记-3图流)