zoukankan      html  css  js  c++  java
  • 用“道”的思想解决费用流问题---取/不取皆是取 (有下界->有上界) / ACdreamoj 1171

    题意: 给一个矩阵,给出约束:i(0<i<n)行至少去ai个数,j行至少取bi个数,要求取的数值之和最小。

          开始一见,就直接建了二分图,但是,发现这是有下界无上界最小费用流问题,肿么办。。。问题转化:所谓正难则反!现在某行/列要至少取k个,总和最小,不就是那行/列最多留下K个,使留下的和最大?其实也就是最多取k个,使值最大,转化为下界为0,有上界的最大费用问题(普通问题)。“取”,“不取”,本质都是一样的,正是“无为”的思想!取,则最小;不取,最大。道也。道之道非常道,名可名非常名~~

    还有一点,转化之后,最大费用时未必最大流。解决方法有二:

    其一:每次增广后,加判断,若费用开始递减,则跳出,此时取最大。(据说二分图费用是先增后减函数:每次增广,当费用最大的时候,但是这时候流量不是最大,所以减小费用来增大流量,不知道一般图是不是。。。)

    其二:释放法,X部所有点直接向汇点连边,费用0,流量Inf,我感觉这样,当X部还有流量的时候,直接就向汇点释放了,所有必是最大费用(不会再减少了)。

    俩种方法我都试过,AC。

    #include<cstdio>
    #include<iostream>
    #include<queue>
    #include<cstring>
    #include<string>
    using namespace std;
    const int maxv=200;
    const int maxe=200*200*2+800;
    const int inf=0x3f3f3f3f;
    int nume=0;int e[maxe][4];int head[maxv];
    int n,m;int ss,tt;
    int val[105][105];
    void inline adde(int i,int j,int c,int w)
    {
        e[nume][0]=j;e[nume][1]=head[i];head[i]=nume;
        e[nume][2]=c;e[nume++][3]=w;
        e[nume][0]=i;e[nume][1]=head[j];head[j]=nume;
        e[nume][2]=0;e[nume++][3]=-w;
    }
    int inq[maxv];int pre[maxv];int prv[maxv];
    int d[maxv];
    bool spfa(int &sum,int &flow)
    {
        for(int i=0;i<=tt;i++)
              {
                  inq[i]=0;
                  d[i]=inf;
              }
        queue<int>q;
        q.push(ss);
        inq[ss]=1;
        d[ss]=0;
        while(!q.empty())
        {
            int cur=q.front();
            q.pop();
            inq[cur]=0;
            for(int i=head[cur];i!=-1;i=e[i][1])
            {
                int v=e[i][0];
                if(e[i][2]>0&&d[cur]+e[i][3]<d[v])
                {
                    d[v]=d[cur]+e[i][3];
                    pre[v]=i;
                    prv[v]=cur;
                    if(!inq[v])
                    {
                        q.push(v);
                        inq[v]=1;
                    }
                }
            }
        }
        if(d[tt]==inf)return 0;
        int cur=tt;
        int minf=inf;
        while(cur!=ss)
        {
            int fe=pre[cur];
            minf=e[fe][2]<minf?e[fe][2]:minf;
            cur=prv[cur];
        }
         cur=tt;
        while(cur!=ss)
        {
            e[pre[cur]][2]-=minf;
            e[pre[cur]^1][2]+=minf;
            cur=prv[cur];
        }
        flow+=minf;
        sum+=d[tt]*minf;
        return 1;
    }
    int mincost(int &flow)
    {
        int sum=0;
       // int lastsum=0;
       while(spfa(sum,flow))
       {
           ;
         //  if(-lastsum>-sum)return lastsum;                  //取最值法
          //  lastsum=sum; // cout<<sum<<endl;
       }
        return sum;
    }
    int sum_all=0;
    void init()
    {
        nume=0; sum_all=0;
        ss=n+m; tt=n+m+1;
        for(int i=0;i<=tt;i++)
           head[i]=-1;
    }
    void read_build()
    {
        for(int i=0;i<n;i++)
         for(int j=0;j<m;j++)
             {
                 scanf("%d",&val[i][j]);
                 sum_all+=val[i][j];
                 adde(i,j+n,1,-val[i][j]);
             }
          int aa;
         for(int i=0;i<n;i++)
         {
            scanf("%d",&aa);
            adde(ss,i,m-aa,0);
            adde(i,tt,m-aa,0);                            //X部直接向汇点连边(容量够释放就行)
         }
           for(int i=0;i<m;i++)
         {
            scanf("%d",&aa);
            adde(i+n,tt,n-aa,0);
         }
       /*  for(int i=0;i<=m+n+1;i++)
           for(int j=head[i];j!=-1;j=e[j][1])
           {
               printf("%d->%d:f %dw %d
    ",i,e[j][0],e[j][2],e[j][3]);
           }*/
    }
    int main()
    {
        int T;
        cin>>T;
        while(T--)
        {
            scanf("%d%d",&n,&m);
            init();
            read_build();
            int flow=0;
            int ans=sum_all+mincost(flow);
             printf("%d
    ",ans);
        }
        return 0;
    }
    
    
    


  • 相关阅读:
    [PHP] thinkphp5 单入口多个模块绑定和路由开关
    [高并发]幂等性、最终一致性
    [高并发]Beanstalkd消息中间件使用
    [高并发]Redis 集群搭建步骤
    [PHP] laravel5.5 搭建流程
    [PHP] 破Laravel白屏问题
    talk 64
    linux
    yum
    linux修改时区
  • 原文地址:https://www.cnblogs.com/yezekun/p/3925777.html
Copyright © 2011-2022 走看看