用“道”的思想解決費用流問題---取/不取皆是取 (有下界->有上界) / ACdreamoj 1171,acdreamoj1171

來源:互聯網
上載者:User

用“道”的思想解決費用流問題---取/不取皆是取 (有下界->有上界) / ACdreamoj 1171,acdreamoj1171

題意: 給一個矩陣,給出約束: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\n",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\n",ans);    }    return 0;}





聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.