zoukankan      html  css  js  c++  java
  • [Wf2011]Chips Challenge

    两个条件都不太好处理

    每行放置的个数实际很小,枚举最多放x

    但还是不好放

    考虑所有位置先都放上,然后删除最少使得合法

    为了凑所有的位置都考虑到,把它当最大流

    但是删除最少,所以最小费用

    行列相关,左行点,右列点

    S到行,流“能填位置”费0

    列到T,流“能填位置”费0

    i行到i列,流x,即枚举的最大个数

    空位(i,j),i行连j列,流1费0

    最小费用最大流

    意义:流过i行到i列的流量,象征留下一个芯片

    流过费用为1的,象征把这个芯片删除。

    最大流保证所有位置都考虑到了

    最小费用使得最少。

    可以发现最后的结果一定满足条件1

    条件2?

    最大流为flow,费用为cos,总共的位置(多出来的+必填)=sum

    放置了tot=sum-cos

    如果有x/tot<=A/B那么更新ans=max(ans,tot)
    x一定时,tot越大,越可能比A/B小。和最小费用相符。

    虽然可能x过大,但是答案一定可以枚举到。

    代码:

    #include<bits/stdc++.h>
    #define reg register int
    #define il inline
    #define numb (ch^'0')
    using namespace std;
    typedef long long ll;
    il void rd(int &x){
        char ch;x=0;bool fl=false;
        while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
        for(x=numb;isdigit(ch=getchar());x=x*10+numb);
        (fl==true)&&(x=-x);
    }
    namespace Miracle{
    const int N=42;
    const int P=86;
    const int inf=0x3f3f3f3f;
    int n,A,B;
    struct node{
        int nxt,to;
        int c,w;
    }e[2*(N*N+2*N)+233];
    int hd[P],cnt=1;
    int s,t;
    void add(int x,int y,int w,int c){
        e[++cnt].nxt=hd[x];
        e[cnt].to=y;
        e[cnt].c=c;
        e[cnt].w=w;hd[x]=cnt;
        
        e[++cnt].nxt=hd[y];
        e[cnt].to=x;
        e[cnt].c=-c;
        e[cnt].w=0;hd[y]=cnt;
    }
    int dis[P];
    bool in[P];
    int incf[P],pre[P];
    queue<int>q;
    int ans,flow,cos;
    int l[N],h[N];
    char mp[N][N];
    bool spfa(){
        memset(dis,inf,sizeof dis);
        memset(pre,0,sizeof pre);
        while(!q.empty()) q.pop();
        dis[s]=0;
        incf[s]=inf;
        q.push(s);
        while(!q.empty()){
            int x=q.front();q.pop();
            in[x]=0;
            for(reg i=hd[x];i;i=e[i].nxt){
                int y=e[i].to;
                if(e[i].w){
                    if(dis[y]>dis[x]+e[i].c){
                        dis[y]=dis[x]+e[i].c;
                        pre[y]=i;
                        incf[y]=min(incf[x],e[i].w);
                        if(!in[y]){
                            in[y]=1;
                            q.push(y);
                        }
                    }
                }
            }
        }
        if(dis[t]==inf) return false;
        return true;
    }
    void upda(){
        int x=t;
        while(pre[x]){
            e[pre[x]].w-=incf[t];
            e[pre[x]^1].w+=incf[t];
            x=e[pre[x]^1].to;
        }
        flow+=incf[t];
        cos+=dis[t]*incf[t];
    }
    void EK(int lim){
        cos=0;flow=0;
        memset(hd,0,sizeof hd);
        cnt=1;
        s=0,t=2*n+1;
        for(reg i=1;i<=n;++i) {
            add(s,i,l[i],0);
            add(i+n,t,h[i],0);
            add(i,i+n,lim,0);
        }
        for(reg i=1;i<=n;++i){
            for(reg j=1;j<=n;++j){
                if(mp[i][j]=='.') add(i,j+n,1,1);
            }
        }
        while(spfa()) upda();
    }
    void clear(){
        ans=-2333;
        for(reg i=1;i<=n;++i) l[i]=n;
        for(reg j=1;j<=n;++j) h[j]=n;
    }
    int main(){
        int o=0;
        while(1){
            rd(n);rd(A);rd(B);
            if(n==0&&A==0&&B==0) break;
            ++o;
            clear();
            int can=0;
            int alr=0;
            for(reg i=1;i<=n;++i){
                scanf("%s",mp[i]+1);
                for(reg j=1;j<=n;++j){
                    if(mp[i][j]=='/') --l[i],--h[j];
                    else ++can;
                    if(mp[i][j]=='C') ++alr;
                }
            }
            for(reg x=0;x<=n;++x){
                EK(x);
                int tot=can-cos;
                if(flow==can&&A*tot>=x*B) ans=max(ans,tot);
            }
            ans-=alr;
            printf("Case %d: ",o);
            if(ans<0) printf("impossible");
            else printf("%d",ans);
            puts("");
        }
        return 0;
    }
    
    }
    signed main(){
        Miracle::main();
        return 0;
    }
    
    /*
       Author: *Miracle*
       Date: 2019/1/8 10:23:22
    */
    View Code

    最小费用最大流可以考虑两个限制

    最大流限制合法

    费用流限制优秀

  • 相关阅读:
    视觉里程计VO-直接法
    Linux安装libcholmod-dev找不到的解决方法
    Levenberg-Marquadt Method
    Gauss-Newton Method
    CMake
    方差 标准差 协方差
    SFM
    矩阵分解
    kvm学习笔记
    python学习笔记
  • 原文地址:https://www.cnblogs.com/Miracevin/p/10240170.html
Copyright © 2011-2022 走看看