zoukankan      html  css  js  c++  java
  • bzoj 3961: [WF2011]Chips Challenge【最小费用最大流】

    参考:https://blog.csdn.net/Quack_quack/article/details/50554032
    神建图系列
    首先把问题转为全填上,最少扣下来几个能符合条件
    先考虑第2个条件,枚举f为一个每行/列最大剩几个,然后记录一下每行列的零件个数(包括填上的)
    然后建图
    s向所有行连流量为这行的零件数的边,所有列向t连流量为这列的零件数的边,i行向i列连流量为f的边,表示这行列最多流f,每个能扣下来的(i,j)连i行j列,因为这个要尽量小而且需要计数,所以附加上1的价值(别的边都为0),然后跑最小费用最大流,判合法有两个条件:1,总流量为总零件数(满流),因为选和不选都能在图上流过去;2,fb<=(sum-val)a
    以及我之前写的费用流板子都是错的???
    而且这个好像不能动态加流量,只能枚举着重建图。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    using namespace std;
    const int N=105,inf=1e9;
    int n,a,b,h[N],cnt,s,t,flo,val,dis[N],fr[N];
    char p[N][N];
    bool v[N],vis[N];
    struct qwe
    {
        int ne,no,to,va,c;
    }e[N*N];
    void add(int u,int v,int w,int c)
    {
        cnt++;
        e[cnt].ne=h[u];
        e[cnt].no=u;
        e[cnt].to=v;
        e[cnt].va=w;
        e[cnt].c=c;
        h[u]=cnt;
    }
    void ins(int u,int v,int w,int c)
    {//cerr<<u<<" "<<v<<" "<<w<<" "<<c<<endl;
        add(u,v,w,c);
        add(v,u,0,-c);
    }
    bool spfa()
    {
        memset(v,0,sizeof(v));
        queue<int>q;
        for(int i=s;i<=t;i++)
            dis[i]=inf;
        dis[s]=0;
        v[s]=1;
        q.push(s);
        while(!q.empty())
        {
            int u=q.front();//cerr<<u<<endl
            q.pop();
            v[u]=0;
            for(int i=h[u];i;i=e[i].ne)
                if(e[i].va>0&&dis[e[i].to]>dis[u]+e[i].c)
                {
                    dis[e[i].to]=dis[u]+e[i].c;
                    fr[e[i].to]=i;
                    if(!v[e[i].to])
                        v[e[i].to]=1,q.push(e[i].to);
                }
        }
        return dis[t]!=inf;
    }
    // void mcf()
    // {
        // int x=inf;
        // for(int i=fr[t];i;i=fr[e[i].no])
            // x=min(x,e[i].va);//,cerr<<e[i].to<<" ";cerr<<endl;
        // flo+=x;
        // for(int i=fr[t];i;i=fr[e[i].no])
        // {
            // e[i].va-=x;
            // e[i^1].va+=x;
            // val+=x*e[i].c;
        // }
    // }
    inline int dfs(int u,int f) 
    {
        if(u==t) return f;
        int us=0;
        vis[u]=1;
        for(int i=h[u];i&&us<f;i=e[i].ne)
            if(e[i].va>0&&!vis[e[i].to]&&dis[e[i].to]==dis[u]+e[i].c) 
            {
                int t=dfs(e[i].to,min(f,e[i].va));
                us+=t;
                val+=e[i].c*t ,
                e[i].va-=t,e[i^1].va+=t;
            }
        if(!us) 
            dis[u]=inf;
        vis[u]=0;
        return us;
    }
    int main()
    {
        for(int cas=1;;cas++)
        {
            scanf("%d%d%d",&n,&a,&b);
            if(n+a+b==0)
                break;
            int sum=0,con=0,r[45],c[45],ans=-1;
            cnt=1,s=0,t=2*n+1,flo=0,val=0;
            memset(h,0,sizeof(h));
            memset(r,0,sizeof(r));
            memset(c,0,sizeof(c));
            for(int i=1;i<=n;i++)
            {
                scanf("%s",p[i]+1);
                for(int j=1;j<=n;j++)
                    if(p[i][j]!='/')
                    {
                        sum++,r[i]++,c[j]++;
                        if(p[i][j]=='C')
                            con++;
                        // else
                            // ins(i,j+n,1,1);
                    }
            }
            // for(int i=1;i<=n;i++)
                // ins(s,i,r[i],0),ins(i+n,t,c[i],0);
            // int st=cnt+1;
            // for(int i=1;i<=n;i++)
                // ins(i,i+n,0,0);
            // while(spfa())
                // mcf();
            //cerr<<flo<<" "<<val<<endl;
            // if(flo==sum&&(sum-val)*a>=0)
                // ans=max(ans,sum-val);
            // for(int f=1;f<=n;f++)
            // {
                // for(int i=st;i<=cnt;i+=2)
                    // e[i].va++;
                // while(spfa())
                    // mcf();
                // cerr<<flo<<" "<<val<<endl;
                // if(flo==sum&&(sum-val)*a>=f*b)
                    // ans=max(ans,sum-val);
            // }
            for(int f=0;f<=n;++f)
            {
                memset(h,0,sizeof h);
                flo=val=s=0;cnt=1;
                t=n*2+1;
                for(int i=1;i<=n;++i)
                {
                    ins(s,i,r[i],0);
                    ins(i+n,t,c[i],0);
                    ins(i,i+n,f,0);
                    for(int j=1;j<=n;++j)
                        if(p[i][j]=='.')
                            ins(i,j+n,1,1);
                }
                while(spfa())
                    flo+=dfs(s,inf);
                if(flo==sum&&f*b<=(sum-val)*a)
                    ans=max(ans,sum-val);
            }
            printf("Case %d: ",cas);
            if(ans==-1)
                puts("impossible");
            else
                printf("%d
    ",ans-con);
        }
        return 0;
    }
    /*
    2 1 1
    /.
    //
    2 50 100
    /.
    C/
    0 0 0
    */
    
  • 相关阅读:
    当期所得税费用总额
    所得税净利润算法
    [AGC028B]Removing Blocks 概率与期望
    bzoj 4319: cerc2008 Suffix reconstruction 贪心
    bzoj 2430: [Poi2003]Chocolate 贪心
    BZOJ 2839: 集合计数 广义容斥
    luogu 5505 [JSOI2011]分特产 广义容斥
    CF504E Misha and LCP on Tree 后缀自动机+树链剖分+倍增
    CF798D Mike and distribution 贪心
    CF707D Persistent Bookcase 可持久化线段树
  • 原文地址:https://www.cnblogs.com/lokiii/p/8926935.html
Copyright © 2011-2022 走看看