zoukankan      html  css  js  c++  java
  • poj1149 PIGS 最大流(神奇的建图)

      一开始不看题解,建图出错了。后来发现是题目理解错了。

       if Mirko wants, he can redistribute the remaining pigs across the unlocked pig-houses. 

      题目中的这句话非常关键,没理解就错掉了。有很多人写的题解只告诉我们怎么做,却没告诉我们为什么要那样做。

      这句话是的意思是可以重组打开过的猪圈。也就是当客人打开猪圈(他能打开的都打开了)以后,他选择了需要买的猪以后,Mirko可以随意把剩下的猪分配到打开的猪圈中。当然,我们追求的是最好的分配方式。

      下面来分析样例是怎么来的:

      第一个顾客打了了第一、第二个猪圈,选择了两头猪。剩下两头猪。Mirko把这两头猪全部放进了第二个猪圈。根据第三步,可以知道这是最好的分配方式。

      第二个顾客打开了第一、第三个猪圈以后,选走了3头。剩下的猪随便分配到第一、第三个猪圈对后面没影响。

      第三个顾客打开了第二个猪圈,买走两头。(最多只能有两头,就是第一步分配的)。

      2+3+2=7

      

      明白了题意,然后才去向怎么建图。建图的方法其他人的博客里写得非常好了。可以参考他们的.

      http://blog.csdn.net/wangjian8006/article/details/7932947  这个博客里有一个网络流建模汇总的链接,可以去下载http://wenku.baidu.com/view/0ad00abec77da26925c5b01c.html

      http://www.cnblogs.com/-sunshine/archive/2012/08/21/2648683.html

      下面是我的代码:建图用的是链式前向星

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int N=1110;
    const int M=2*N*N, INF=1000000;
    struct node
    {
        int to,next,w;
    }edge[M];
    int head[N],numh[N],h[N],cure[N],pre[N],vis[N],flag[N];
    int ans,tot;
    void SAP(int s, int e,int n)
    {
        int flow,u,tmp,neck,i;
        ans=0;
        for(i=1;i<=n;i++)
            cure[i]=head[i];
        numh[0]=n;
        u=s;
        while(h[s]<n)
        {
            if(u==e)
            {
                flow =INF;
                for(i=s;i!=e;i=edge[cure[i]].to)
                {
                    if(flow>edge[cure[i]].w)
                    {
                        neck=i;
                        flow =edge[cure[i]].w;
                    }
                }
                for(i=s;i!=e;i=edge[cure[i]].to)
                {
                    tmp=cure[i];
                    edge[tmp].w-=flow;
                    edge[tmp^1].w+=flow;
                }
                ans+=flow;
                u=neck;
            }
            for(i=cure[u];i!=-1;i=edge[i].next)
                if(edge[i].w && h[u]==h[edge[i].to]+1) break;
            if(i!=-1) {cure[u]=i;pre[edge[i].to]=u;u=edge[i].to;}
            else
            {
                if(0==--numh[h[u]]) break; //GAP优化
                cure[u]=head[u];
                for(tmp=n,i=head[u];i!=-1;i=edge[i].next)
                    if(edge[i].w) tmp=min(tmp, h[edge[i].to]);
                h[u]=tmp+1;
                ++numh[h[u]];
                if(u!=s) u=pre[u];
            }
        }
    }
    void init()
    {
        tot=0;
        memset(head,-1,sizeof(head));
        memset(pre,-1,sizeof(pre));
        memset(h,0,sizeof(h));
        memset(numh,0,sizeof(numh));
        memset(vis,0,sizeof(vis));
        memset(flag,0,sizeof(flag));
    }
    void addedge(int i,int j,int w)
    {
        edge[tot].to=j;edge[tot].w=w;edge[tot].next=head[i];head[i]=tot++;
        edge[tot].to=i;edge[tot].w=0;edge[tot].next=head[j];head[j]=tot++;
    }
    int pg[N];
    int main()
    {
        //猪圈的编号1 ~m ,人的编号是m+1 ~ m+n
        //freopen("test.txt","r",stdin);
        int m,n,i,j,k,a,b,t,s,e;
        while(scanf("%d%d",&m,&n)!=EOF)
        {
            init();
            s=n+1; e=s+1;
            for(i=1;i<=m;i++)
            {
                scanf("%d",&pg[i]);
            }
            for(k=1;k<=n;k++)
            {
                scanf("%d",&a);
                for(i=0;i<a;i++)
                {
                    scanf("%d",&j);
                    if(!vis[j])//猪圈j没有打开过
                    {
                        if(!flag[k]) //顾客k没有打开过猪圈
                        {
                            addedge(s,k,pg[j]);
                            flag[k]=tot-2;//-2别弄错了
                        }
                        else
                        {
                            edge[flag[k]].w+=pg[j];
                        }
                        vis[j]=k;
                    }
                    else
                    {
                        addedge(vis[j],k,INF);
                        vis[j]=k;
                    }
                }
                scanf("%d",&b);
                addedge(k,e,b);
            }
            SAP(s,e,e);
            printf("%d
    ",ans);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    BZOJ3752 : Hack
    XIV Open Cup named after E.V. Pankratiev. GP of SPb
    XIII Open Cup named after E.V. Pankratiev. GP of Ukraine
    BZOJ2087 : [Poi2010]Sheep
    BZOJ2080 : [Poi2010]Railway
    BZOJ2082 : [Poi2010]Divine divisor
    Moscow Pre-Finals Workshop 2016. National Taiwan U Selection
    XIII Open Cup named after E.V. Pankratiev. GP of Asia and South Caucasus
    XIII Open Cup named after E.V. Pankratiev. GP of Azov Sea
    XIII Open Cup named after E.V. Pankratiev. GP of SPb
  • 原文地址:https://www.cnblogs.com/Potato-lover/p/3970493.html
Copyright © 2011-2022 走看看