• Firing POJ


    最大权闭合子图:一张图,一些点权值为正,一些点权值为负,选了一些点必须选择器后继节点,问权值最大的子图。

    考虑最小割做法:

    源点向点权为正的点连边,点权为负的点向汇点连边,其他点两两连边流量为inf,求最小割为答案。

    设  点权为正的点与源点连边表示选择这个点

    设  点权为负的点与源点连边表示不选择这个点

    如果图联通:选择一个点又不选择后继节点,与闭合子图的定义矛盾,所以图必然不连通。

    求一遍最小割:实际上是 不选择的点权为正的点+选择的点权为负的绝对值。保证最小。

    那么:最大权闭合子图的权值为:正点权和-(不选择的点权为正的点+选择的点权为负的绝对值)

    Firing

     POJ - 2987 
    #include<cstdio>
    #include<cmath>
    #include<queue>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int N=1e5+500;
    typedef long long ll;
    const ll INF=1e17;
    int n,m,S,T;
    struct Dinic{
        int head[N],dep[N];
        int ecnt,cnt; 
        int vis[N];
        struct edge{
            int v,next;ll flow;
        }e[N*10];
    
        void init(){
            memset(head, -1, sizeof head);
            ecnt = cnt=0;
            memset(vis,0,sizeof vis);
        }
    
        void addedge(int u, int v, ll flow) {
        e[ecnt].v=v;e[ecnt].flow=flow;e[ecnt].next=head[u];head[u]=ecnt++;
        e[ecnt].v=u;e[ecnt].flow=0;e[ecnt].next=head[v];head[v]=ecnt++;
        }
    
        bool BFS(){//分层图找增广路
            memset(dep,0,sizeof dep);
            queue<int>Q;
            Q.push(S);dep[S]=1;
            while(!Q.empty()){
                int u=Q.front();Q.pop();
                for(int i=head[u];~i;i=e[i].next){
                    if(e[i].flow&&!dep[e[i].v]){
                        dep[e[i].v]=dep[u]+1;
                        Q.push(e[i].v);
                    }
                }
            }
            return dep[T];
        }
        void cut(int u){
            vis[u]=1;
            cnt++;
            for(int i=head[u];~i;i=e[i].next){
                int v=e[i].v;
                if(e[i].flow&&!vis[v])cut(v);
            }
        }
        ll DFS(int u,ll f){//推进新流
            if(u==T||f==0)return f;
            ll w,used=0;
            for(int i=head[u];~i;i=e[i].next){
                if(e[i].flow&&dep[e[i].v]==dep[u]+1){
                    w=DFS(e[i].v,min(f,e[i].flow));//多路增广
                    e[i].flow-=w;e[i^1].flow+=w;
                    used+=w;f-=w;
                }
            }
            if(!used)dep[u]=-1;//炸点优化
            return used;
        }
    
        ll  maxflow() {
            ll ans=0;
            while(BFS()){
                ans+=DFS(S,INF);
            }
            return ans;
        }
    }dinic;  
    int main(){
        scanf("%d %d",&n,&m);
        dinic.init();
        S=0;T=n+50;
        ll sum=0;
        for(int i=1;i<=n;i++){
            ll p;scanf("%lld",&p);
            if(p>0)dinic.addedge(S,i,p),sum+=p;
            else dinic.addedge(i,T,-p);
        }
    
        while(m--){
            int u,v;scanf("%d %d",&u,&v);
            dinic.addedge(u,v,INF);
        }
    
        ll ans=sum-dinic.maxflow();
        dinic.cut(S);
        cout<<dinic.cnt-1<<" "<<ans<<endl;
    
        // system("pause");
        return 0;
    }
    View Code

     求最大权闭合子图,输出选择方案,

    构建最大流求闭合子图权,那么所有流量为正的点即为被选择的点。

  • 相关阅读:
    微信小程序
    js
    js
    uni
    uni/微信小程序
    uni/微信小程序
    ES6...扩展运算符(数组或类数组对象)
    微信小程序
    微信小程序
    玩转storm
  • 原文地址:https://www.cnblogs.com/littlerita/p/13461749.html
Copyright © 2020-2023  润新知