zoukankan      html  css  js  c++  java
  • 洛谷3381

    最小费用最大流模板题

    思路和网络流的EK算法类似,

    1.建正向边,反向边(反向边流量为0,花费为负数:走反向边即取消上次走过后增加的值,因此如此定义)

    2.用spfa增广,找到流量大于0且由花费决定的最小dis[ t ],接着回溯,找到能通过的最大流量(minn)

    3.ansflow+=minn;anscost+=minn*dis[t];

    4.重复2.3步骤,直至无法增广,即为答案

    #include<cstdio>
    #include<cctype>
    #include<queue>
    #include<cstring>
    #include<algorithm>
    #define INF 0x33333333
    using namespace std;
    const int N=5002,M=50002;
    int n,m,s,t,cnt=-1,vis[N],dis[N],head[N];
    int pv[N],pe[N];
    struct data{int v,flow,cos,next;}edge[2*M];
    queue<int>q;
    
    inline void read(int &x){
        char ch=getchar();x=0;
        while(!isdigit(ch))ch=getchar();
        while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    }
    
    inline bool spfa(int S,int T)
    {
        memset(dis,0x33,sizeof dis);
        memset(vis,0,sizeof vis);
        q.push(S),vis[S]=1,dis[S]=0;
        while(!q.empty())
        {
            int now=q.front();q.pop();vis[now]=0;
            for (int i=head[now];~i;i=edge[i].next)//注意不是i>0;会出现第0条边 
                if (edge[i].flow>0 && dis[edge[i].v]>dis[now]+edge[i].cos)
                {
                    dis[edge[i].v]=dis[now]+edge[i].cos;
                    pe[edge[i].v]=i,pv[edge[i].v]=now;
                    if (!vis[edge[i].v])
                        vis[edge[i].v]=1,q.push(edge[i].v);
                }
        }
        return dis[T]<INF;
    }
    
    inline void Putans(int x){
        if(x>=10)Putans(x/10);putchar(x%10+'0');
    }
    
    inline void mfmc(int S,int T){
        int Cos=0,Flow=0,minn;
        while(spfa(S,T)){
            minn=INF;
            for(int i=T;i!=S;i=pv[i])minn=min(minn,edge[pe[i]].flow);
            Cos+=minn*dis[T];
            Flow=Flow+minn;
            for(int i=T;i!=S;i=pv[i]){edge[pe[i]].flow-=minn;edge[pe[i]^1].flow+=minn;}
        }
        Putans(Flow);printf(" ");Putans(Cos);//printf("%d %d",Flow,Cos);
    }
    
    inline void insert(int u,int v,int flow,int cost){
        edge[++cnt].v=v;
        edge[cnt].flow=flow;edge[cnt].cos=cost;edge[cnt].next=head[u];head[u]=cnt;
    }
    
    int main(){
        read(n);read(m);read(s);read(t);
        memset(head,-1,sizeof(head));//一定要赋值-1,否则spfa时出现第0条边,无限循环 
        memset(edge,-1,sizeof(edge));
        for(int i=1;i<=m;i++){//tot初值为-1(保证 ^1后是反向边) 
            int u,v,flow,cost;
            read(u);read(v);read(flow);read(cost);
            insert(u,v,flow,cost);insert(v,u,0,-cost);//flow要赋值0,否则其初值为-1  
        }
        mfmc(s,t);
    }
  • 相关阅读:
    计算机学习的网站、常用软件
    c语言标识符
    Git报错
    福尔摩斯的约会
    怎样判断一个单链表是否有环?
    中成药的合理使用--风寒感冒
    使用vscode打造python开发环境
    AIDA64 Extreme 6.10.5200 序列号
    VMware Workstation Pro 15密钥及下载地址
    centos 一键安装 Aria2 &管理脚本
  • 原文地址:https://www.cnblogs.com/MikuKnight/p/8888361.html
Copyright © 2011-2022 走看看