zoukankan      html  css  js  c++  java
  • hdu3879 网络流(经典最大获利问题)

    这题建图自己想了半天搞不懂,然后看了一下别人的建图。。。一脸茫然。。

    最后去看了下胡波涛的《最小割模型在信息学竞赛的应用》里面详细的讲解了将最大获利问题转换为最小割模型的过程。

    建图:

    源点与人连边,容量为获利。站点与汇点连边,容量为耗资。然后是相应的人与其需求的站点连边,容量为无穷。

    这样建图就完成了,然后就是找最小割,即割边上的值便为不能获取的利润值,用总值减去得出最大利润。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #define MAXN 60000              //点的个数
    #define INF 1e8
    #define min(a,b) (a<b?a:b)
    #define max(a,b) (a>b?a:b)
    using namespace std;
    struct edge
    {
        int u,v,w,next;
    }E[400050];                     //边的个数  记得乘2
    int head[MAXN],ecnt;
    int gap[MAXN],cur[MAXN],pre[MAXN],dis[MAXN];
    int l,r,mid;
    int N,M,scr,sink,vn,num;
    void Insert(int u,int v,int w)
    {
        E[ecnt].u=u;
        E[ecnt].v=v;
        E[ecnt].w=w;
        E[ecnt].next=head[u];
        head[u]=ecnt++;
        E[ecnt].u=v;
        E[ecnt].v=u;
        E[ecnt].w=0;
        E[ecnt].next=head[v];
        head[v]=ecnt++;
    }
    int Sap(int s,int t,int n)//核心代码(模版)
    {
        int ans=0,aug=INF;//aug表示增广路的流量
        int i,v,u=pre[s]=s;
        for(i=0;i<=n;i++)
        {
            cur[i]=head[i];
            dis[i]=gap[i]=0;
        }
        gap[s]=n;
        bool flag;
        while(dis[s]<n)
        {
            flag=false;
            for(int &j=cur[u];j!=-1;j=E[j].next)//一定要定义成int &j,why
            {
                v=E[j].v;
                if(E[j].w>0&&dis[u]==dis[v]+1)
                {
                    flag=true;//找到容许边
                    aug=min(aug,E[j].w);
                    pre[v]=u;
                    u=v;
                    if(u==t)
                    {
                        ans+=aug;
                        while(u!=s)
                        {
                            u=pre[u];
                            E[cur[u]].w-=aug;
                            E[cur[u]^1].w+=aug;//注意
                        }
                        aug=INF;
                    }
                    break;//找到一条就退出
                }
            }
            if(flag) continue;
            int mindis=n;
            for(i=head[u];i!=-1;i=E[i].next)
            {
                v=E[i].v;
                if(E[i].w>0&&dis[v]<mindis)
                {
                    mindis=dis[v];
                    cur[u]=i;
                }
            }
            if((--gap[dis[u]])==0) break;
            gap[dis[u]=mindis+1]++;
            u=pre[u];
        }
        return ans;
    }
    int n,m;
    int main()
    {
       while(scanf("%d%d",&n,&m)!=EOF)
       {
           memset(head,-1,sizeof(head));ecnt=0;
           scr=0;sink=n+m+1;vn=sink+1;
           for(int i=1;i<=n;i++)
           {
               int v;
               scanf("%d",&v);
               Insert(i,sink,v);
           }
           int sum=0;
           for(int i=1;i<=m;i++)
           {
               int a,b,v;
               scanf("%d%d%d",&a,&b,&v);
               Insert(scr,i+n,v);
               Insert(i+n,a,INF);
               Insert(i+n,b,INF);
               sum+=v;
           }
            printf("%d\n",sum-Sap(scr,sink,vn));
       }
       return 0;
    }
    


     

  • 相关阅读:
    leetcode| Intersection of Two Arrays II
    Spring Boot起步依赖:定制starter
    SpringBoot自动配置的魔法是怎么实现的
    Dubbo中的IoC实现
    必须知道的String知识点
    Dubbo的SPI机制
    为什么要设置HTTP timeout?
    重构代码——简单工厂模式+模板方法模式
    计算机基础——位运算
    系统间HTTP调用代码封装
  • 原文地址:https://www.cnblogs.com/amourjun/p/5134142.html
Copyright © 2011-2022 走看看