zoukankan      html  css  js  c++  java
  • poj2135 最小费用流

    对于最小费用流,基本的思想和最大流类似,不断寻找增广路增广,只是此时还要考虑费用问题。

    寻找最大流的方法是从某个可行流出发,找到关于这个流的一条增广路P; 

    沿着P调整f,对新的可行流又试图寻找关于它的增广路,循环直至不存在增广路为止; 

    如果f是流量为f1的可行流中费用最小者,而p是关于f的所有增广路中费用最小的增广路; 

    那么沿着p去调整f,得到可行流_f,就是流量为f1的所有可行流中的费用最小者; 

    这样当f是最大流时,它也就是所要求的最小费用最大流了; 

     详见代码注释。

    #include<stdio.h>
    #include<string.h>
    #include<queue>
    #define INF 99999999
    using namespace std;
    const int maxn = 1002;
    struct node
    {
        int to;
        int f;
        int cost;
        int flag;
        int next;
    }edge[maxn*maxn/2];
    int index,head[maxn],vis[maxn],dis[maxn],n,pre[maxn],fpre[maxn];//由于是邻接表 直接找到点并不能找到值 所以fpre存取到该点的index
    void init()
    {
        index=1;
        memset(head,-1,sizeof(head));
    }
    void add(int x,int y,int v,int cost)
    {
        edge[index].to=y;
        edge[index].f=v;
        edge[index].cost=cost;
        edge[index].next=head[x];
        edge[index].flag=index+1;
        head[x]=index++;
        edge[index].to=x;
        edge[index].f=0;
        edge[index].cost=-cost;
        edge[index].next=head[y];
        edge[index].flag=index-1;
        head[y]=index++;
    }
    bool spfa(int s,int t)
    {
        int i,j;
        queue<int>q;
        memset(pre,-1,sizeof(pre));//pre记录路径
        memset(vis,0,sizeof(vis));
        for(i=0;i<=t;i++)
            dis[i]=INF;
        dis[s]=0;
        vis[s]=1;
        pre[s]=0;
        q.push(s);
        while(!q.empty())
        {
            int temp=q.front();
            q.pop();
            vis[temp]=0;
            for(i=head[temp];i!=-1;i=edge[i].next)
            {
                if(edge[i].f&&dis[edge[i].to]>dis[temp]+edge[i].cost)//可以松弛并且可行流
                {
                    dis[edge[i].to]=dis[temp]+edge[i].cost;
                    if(!vis[edge[i].to])
                    {
                        vis[edge[i].to]=1;
                        q.push(edge[i].to);
                    }
                    pre[edge[i].to]=temp;
                    fpre[edge[i].to]=i;
                }
            }
        }
        if(dis[t]>=INF)
            return false;
        return true;
    }
    void MCMF(int s,int t)//最小费用流
    {
        int i,j;
        int ans=0;
        while(spfa(s,t))//最短路寻找小的费用 即是否还有增广路
        {
            int minflow=INF;
            for(i=t;i!=0;i=pre[i])//在费用最小的情况下 寻找可行的流量
            {
                if(minflow>edge[fpre[i]].f)
                    minflow=edge[fpre[i]].f;
            }
            ans+=minflow*dis[t];//费用
            for(i=t;i!=0;i=pre[i])
            {
                edge[fpre[i]].f-=minflow;//正向的减
                edge[edge[fpre[i]].flag].f+=minflow;//反向加
            }
        }
        printf("%d
    ",ans);
    }
    int main()
    {
        int i,j,m;
        while(~scanf("%d%d",&n,&m))
        {
            init();
            int x,y,z;
            for(i=0;i<m;i++)
            {
                scanf("%d%d%d",&x,&y,&z);
                add(x,y,1,z);
                add(y,x,1,z);
            }
            int s=0,t=n+1;
            add(s,1,2,0);//源点到出发点容量为2 费用0
            add(n,t,2,0);//到汇点的容量为2,费用0
            MCMF(s,t);
        }
    }
  • 相关阅读:
    c#的Marshal
    爬虫之requests详解
    爬取抖音视频
    爬取拉钩网
    爬虫自动登陆GitHub
    爬取博客园博客
    爬取煎蛋网文章
    爬取抽屉热搜榜文章
    准备
    爬虫示例
  • 原文地址:https://www.cnblogs.com/sweat123/p/4896436.html
Copyright © 2011-2022 走看看