• 最小费用最大流学习笔记


    最近学了最小费用最大流,写一篇总结

    前置知识:

    • 最小费用的前提条件是最大流(本文提到的最大流算法为Dinic)
    • 对于每条边来说,他们有着不一定相等的单位流量的价格,所以才有了"最小费用"这一条件

    个人理解:

    • 在普通的网络最大流中,常常使用类似while(bfs())while(flow=dinic(s,INF))maxflow+=flow;的方式求得结果
    • 而在最小费用流中,原本的bfs()被替换成了spfa().而原本的bfs()是用来进行分层的,也就是保证始终有一条增广路.如果无法获取新的增广路了,也就可以输出结果了.在最小费用流中,我们在进行bfs的同时增加了对最小费用的剪枝,也就是spfa().

    模板地址:https://www.luogu.org/problemnew/show/P3381


    #include<iostream>
    #include<cstdio>
    #include<queue>
    #include<cstring>
    using namespace std;
    const int MAXN=100100;
    int head[MAXN],cnt=1;
    int dis[MAXN],pre[MAXN],last[MAXN],flow[MAXN];
    bool vis[MAXN];
    struct Edge{
        int to,w,f,nxt;
    }e[MAXN];
    queue<int>q;
    void addEdge(int u,int v,int w,int f){//加边 
        e[++cnt].to=v,e[cnt].w=w,e[cnt].f=f,e[cnt].nxt=head[u],head[u]=cnt;
        e[++cnt].to=u,e[cnt].w=0,e[cnt].f=-f,e[cnt].nxt=head[v],head[v]=cnt;
    }
    bool spfa(int s,int t){
        memset(dis,0x7f,sizeof(dis));//清空数组 
        memset(flow,0x7f,sizeof(flow));
    	pre[t]=0;//将汇点的前继点设为空值 
        q.push(s);//初始化源点 
        dis[s]=0;//初始化dis 
        while(q.size()){//如果队列中还有结点就继续bfs 
            int u=q.front();q.pop();vis[u]=0;//提出点并设置该点并没有访问过 
            for(int i=head[u];i;i=e[i].nxt){
            	int y=e[i].to;
            	int newdis=dis[u]+e[i].f;//到点y的新代价 
                if(e[i].w&&dis[y]>newdis){//如果还有容量并且新路径代价较小 
                    dis[y]=newdis;//设置到点y的代价为新代价 
                    pre[y]=u;//到点y需要经过的点 
                    last[y]=i;//到点y需要经过的边 
                    flow[y]=min(flow[u],e[i].w);//能经过该点的最大流 
                    if(!vis[y]){//如果该点没访问过
                        vis[y]=1;//将该点设为访问过 
                        q.push(y);//向队列中加点 
                    }
                }
            }
        }
        return pre[t];
    }
    int main(){
        int n,m,s,t;
        scanf("%d%d%d%d",&n,&m,&s,&t);
        for(int i=1;i<=m;i++){//输入
        	int u,v,w,f;
            scanf("%d%d%d%d",&u,&v,&w,&f);
            addEdge(u,v,w,f);
        }
        int maxflow=0,mincost=0;
        while(spfa(s,t)){//如果能继续增广 
            maxflow+=flow[t];//增加最大流 
            mincost+=flow[t]*dis[t];//增加最小费用 
            int now=t;//设置当前点为汇点 
            while(now!=s){
                e[last[now]].w-=flow[t];
                e[last[now]^1].w+=flow[t];
                now=pre[now];
            }
        }
        printf("%d %d
    ",maxflow,mincost);//输出答案 
        return 0;
    }
  • 相关阅读:
    《算法竞赛进阶指南》0x12 队列 POJ2259 Team Queue
    《算法竞赛进阶指南》0x11栈 单调栈求矩形面积 POJ2559
    《算法竞赛进阶指南》0x11 栈 求解中缀表达式
    19.职责链模式(Chain of Responsibility Pattern)
    16.观察者模式(Observer Pattern)
    17.解释器模式(Interpreter Pattern)
    15. 迭代器模式(Iterator Pattern)
    14.命令模式(Command Pattern)
    12.代理模式(Proxy Pattern)
    13.模板方法(Template Method)
  • 原文地址:https://www.cnblogs.com/zbsy-wwx/p/11680653.html
Copyright © 2020-2023  润新知