• 最大权闭合子图


    闭合子图

    有向图的一个闭合子图是这个有向图的一个点集,其中所有点的出边连向的还是点集中的点

    最大权闭合子图

    有向图的每个点都有点权(可正可负),能得到的点权最大的闭合子图

    网络流模型

    点权转化为边权,建立新图:
    设立超级源点和超级汇点
    超级源点向点权为正的点连边,流量为点权的绝对值
    点权为负的点向超级汇点连边,流量为点权的绝对值
    所有原图上的边,流量为正无穷

    计算新图的最小割
    原图的最大权闭合子图的最大权为:
    原图中点权为正的点权和减去新图的最小割

    模板题:hdu3061 Battle

    #include<bits/stdc++.h>
    #define LL long long
    #define PII pair<int,int>
    #define PLI pair<LL,int>
    #define lson o<<1,l,mid
    #define rson o<<1|1,mid+1,r
    #define lowbit(x) (x&(-x))
    using namespace std;
    
    const int maxn=510,maxm=2*maxn+100010,inf=1e9+10;
    int n,m,head[maxn],to[2*maxm],nxt[2*maxm],w[2*maxm],cnt;
    int s,t,depth[maxn],cur[maxn],N;
    
    void init(){
        memset(head,-1,sizeof(head));
        cnt=0;
    }
    
    void add(int u,int v,int c){
        to[cnt]=v;
        w[cnt]=c;
        nxt[cnt]=head[u];
        head[u]=cnt++;
    }
    
    void add_edge(int u,int v,int c){
        add(u,v,c);
        add(v,u,0);
    }
    
    int dfs(int u,int flow){
        if(u==t) return flow;
        for(int& i=cur[u];~i;i=nxt[i]){
            int v=to[i];
            if(depth[v]==depth[u]+1 && w[i]!=0){
                int di=dfs(v,min(flow,w[i]));
                if(di>0){
                    w[i]-=di;
                    w[i^1]+=di;
                    return di;
                }
            }
        }
        return 0;
    }
    
    bool bfs(){
        queue<int> q;
        memset(depth,0,sizeof(depth));
        depth[s]=1;
        q.push(s);
        while(!q.empty()){
            int u=q.front();
            q.pop();
            for(int i=head[u];~i;i=nxt[i]){
                int v=to[i];
                if(depth[v]==0 && w[i]>0){
                    depth[v]=depth[u]+1;
                    q.push(v);
                }
            }
        }
        if(depth[t]>0) return 1;
        return 0;
    }
    
    int dinic(){
        int ans=0;
        while(bfs()){
            for(int i=0;i<=N;i++){
                cur[i]=head[i];
            }
            while(int d=dfs(s,inf)){
                ans+=d;
            }
        }
        return ans;
    }
    
    int main(){
        while(scanf("%d %d",&n,&m)!=EOF){
            init();
            s=0;
            t=n+1;
            N=t;
            int ans=0;
            for(int i=1;i<=n;i++){
                int x;
                scanf("%d",&x);
                if(x>0){
                    add_edge(s,i,x);
                    ans+=x;
                }
                else add_edge(i,t,-x);
            }
            for(int i=0;i<m;i++){
                int u,v;
                scanf("%d %d",&u,&v);
                add_edge(u,v,inf);
            }
            printf("%d
    ",ans-dinic());
        } 
    }
    
  • 相关阅读:
    什么是垃圾回收
    Oracle GoldenGate学习之Goldengate介绍
    JVM虚拟机选项:Xms Xmx PermSize MaxPermSize区别
    查看linux系统版本命令
    Case when 的用法,简单Case函数
    case when then else end
    ORACLE视图添加备注
    修改 tomcat 内存
    Linux 内存机制详解宝典
    oracle正则表达式regexp_like的用法详解
  • 原文地址:https://www.cnblogs.com/fxq1304/p/13610204.html
Copyright © 2020-2023  润新知