• P4177 [CEOI2008]order(网络流)最大权闭合子图


     

    P4177 [CEOI2008]order

    如果不能租机器,这就是最大权闭合子图的题:

    给定每个点的$val$,并给出限制条件:如果取点$x$,那么必须取$y_1,y_2,y_3......$,满足$val_x>0,val_{y_i}<0$

    求最大点权和。


     

    对于一个图,跑过最小割(最大流)后

    有若干个点与源点$S$仍连通,我们把这部分点集称为$S$割

    与汇点$T$仍连通的点的点集,称为$T$割

    我们把$S$割内的点视作被取走,$T$割内的点视为不被取。

    考虑建个新图来表示点之间的关系

    在图中,对于$val_i>0$的点$i$,我们做如下操作(link操作包含连边和反向边,即正常的网络流连边):

    $link(S,i,val_i)$:如果该边在最小割中,那么$i$不属于$S$割,即该点没有被取

    取$i$的同时必须取$k$,$link(i,k,inf)$:该边不可能在最小割中,表明$i$、$k$或是都被取,或是不取$i$

    对于$val_i<0$的点:

    $link(i,T,-val_i)$:如果该边在最小割中,那么$i$属于$S$割,取点$i$得到$-val_i$的贡献

    在这样的图上跑最小割,我们就可以得出最小损失的代价$t$

    答案即为$sum_{i=1}^{left | S ight |}val_i-t$(所有$val_i>0$的点$-$代价)


    但是我们可以租机器了

    设$cost_k$为租机器$k$的费用,那么我们可以把租机器看成:花费$cost_k$,让这道工序可以不用机器$k$

    $link(i,k,inf) ightarrow link(i,k,cost_k)$

    蓝后就没了

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    using namespace std;
    void read(int &x){
        char c=getchar();x=0;
        while(c<'0'||c>'9') c=getchar();
        while('0'<=c&&c<='9') x=x*10+(c^48),c=getchar();
    }
    #define N 200005
    #define W 40000005
    #define inf 1000000000
    int n,m,w,tt,id,S,T,d[N],cur[N],tot;
    bool vis[N];
    queue <int> h;
    int cnt=1,hd[N],nxt[W],ed[N],poi[W],val[W];
    inline void adde(int x,int y,int v){
        nxt[ed[x]]=++cnt, hd[x]=hd[x]?hd[x]:cnt,
        ed[x]=cnt, poi[cnt]=y, val[cnt]=v;
    }
    inline void link(int x,int y,int v){adde(x,y,v),adde(y,x,0);}
    bool bfs(){
        memset(vis,0,sizeof(vis));
        h.push(S); vis[S]=1;
        while(!h.empty()){
            int x=h.front();h.pop();
            for(int i=hd[x];i;i=nxt[i]){
                int to=poi[i];
                if(!vis[to]&&val[i])
                    vis[to]=1,d[to]=d[x]+1,h.push(to);
            }
        }return vis[T];
    }
    int dfs(int x,int a){
        if(x==T||a==0) return a;
        int F=0,f;
        for(int &i=cur[x];i;i=nxt[i]){
            int to=poi[i];
            if(d[to]==d[x]+1&&(f=dfs(to,min(a,val[i])))>0)
                a-=f,F+=f,val[i]-=f,val[i^1]+=f;
            if(!a) break;//注意a==0要放到每次循环的最后判!
        }return F;
    }
    int dinic(){
        int re=0;
        while(bfs()){
            for(int i=1;i<=T;++i) cur[i]=hd[i];
            re+=dfs(S,inf);
        }return re;
    }
    int main(){
        read(n);read(m); S=n+m+1; T=S+1;
        for(int i=1;i<=n;++i){
            read(w);read(tt); link(S,i,w); tot+=w;
            while(tt--) read(id),read(w),link(i,id+n,w);
        }
        for(int i=1;i<=m;++i) read(w),link(i+n,T,w);
        printf("%d",tot-dinic());
        return 0;
    }
  • 相关阅读:
    linux系统--磁盘管理命令(二)
    linux系统--磁盘管理命令(一)
    linux系统--用户和用户组
    linux4.10.8 内核移植(四)---字符设备驱动_led驱动程序
    linux4.10.8 内核移植(三)---裁剪内核
    linux4.10.8 内核移植(二)---初步裁剪、分区修改和文件系统
    Linux 4.10.8 根文件系统制作(三)---制作yaffs文件系统
    Kotlin的面向对象入门
    Python 中的GIL
    python 虚拟环境的 安装与 使用 和修改为豆瓣源
  • 原文地址:https://www.cnblogs.com/kafuuchino/p/10770978.html
Copyright © 2020-2023  润新知