• 最大权闭合图


    定义:在一个图中,我们选取一些点构成集合,记为V,且集合中的出边(即集合中的点的向外连出的弧),所指向的终点(弧头)也在V中,则我们称V为闭合图。最大权闭合图即在所有闭合图中,集合中点的权值之和最大的V,我们称V为最大权闭合图。

    做法:首先我们将其转化为一个网络(现在不要问为什么,接下来会证明用网络可以求解)。构造一个源点S,汇点T。我们将S与所有权值为正的点连一条容量为其权值的边,将所有权值为负的点与T连一条容量为其权值的绝对值的边,原来的边将其容量定为正无穷。

    首先引入结论,最小割所产生的两个集合中,其源点S所在集合(除去S)为最大权闭合图,接下来我们来说明一些结论。

    1.最小割为简单割

    简单割的概念:割集的每条边都与S或T关联。(请下面阅读时一定分清最小割与简单割,容易混淆)

    2.网络中的简单割与原图中闭合图存在一一对应的关系。(即所有闭合图都是简单割,简单割也必定是一个闭合图)

    闭合图是简单割:如果闭合图不是简单割(反证法)。那么说明有一条边是容量为正无穷的边,则说明闭合图中有一条出边的终点不在闭合图中,矛盾。

    简单割是闭合图:因为简单割不含正无穷的边,所以不含有连向另一个集合(除T)的点,所以其出边的终点都在简单割中,满足闭合图定义。

    3.最小割所产生的两个集合中,其源点S所在集合(除去S)为最大权闭合图。

     首先我们记一个简单割的容量为C,且S所在集合为N,T所在集合为M。

            则C=M中所有权值为正的点的权值(即S与M中点相连的边的容量)+N中所有权值为负的点权值的绝对值(即N中点与T中点相连边的容量)。记(C=x1+y1);(很好理解,不理解画一个图或想象一下就明白了)。

            我们记N这个闭合图的权值和为W。

            则W=N中权值为正的点的权值-N中权值为负的点的权值的绝对值。记(W=x2-y2);

            则W+C=x1+y1+x2-y2。

            因为明显y1=y2,所以W+C=x1+x2;

            x1为M中所有权值为正的点的权值,x2为N中权值为正的点的权值。

            所以x1+x2=所有权值为正的点的权值之和(记为TOT).

            所以我们得到W+C=TOT.整理一下W=TOT-C.

            到这里我们就得到了闭合图的权值与简单割的容量的关系。

            因为TOT为定值,所以我们欲使W最大,即C最小,即此时这个简单割为最小割,此时闭合图为其源点S所在集合(除去S)。

     http://cogs.pro/cogs/problem/problem.php?pid=727

    /****************************************************************************************************
    
                                        最大权闭合图—最小割
                                            dinic算法 
                            
    
    ********************************************************************************************************/
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define check(c) (c>='0'&&c<='9')
    #define inf 9999999
    struct Edge{
        int next,to,power;
        Edge(){}
        Edge(int next,int to,int power):next(next),to(to),power(power){}
    }edge[10001];
    int f[205],top=1,q[205],l,r,dis[202];
    inline void add_edge(int c,int t,int p){
        edge[++top]=Edge(f[c],t,p);f[c]=top;
        edge[++top]=Edge(f[t],c,0);f[t]=top;
    }
    inline bool in(int& a){
        a=0;char c=getchar();
        while(!check(c))c=getchar();
        while(check(c))a=a*10+c-48,c=getchar();
        return (c!='
    '&&c!='
    ');
    }
    bool bfs(){
        memset(dis,-1,sizeof(dis));dis[0]=1;
        l=0,r=1,q[0]=0;
        while(l<r){
            int v=q[l++],to=f[v],x;
            while(to){
                x=edge[to].to;
                if(dis[x]==-1&&edge[to].power>0){
                    dis[x]=dis[v]+1,q[r++]=x;
                    if(x==201)return 1;
                }
                to=edge[to].next;
            }
        }
        return 0;
    }
    int dfs(int x,int low){//low为到当前节点最大流
        int ans=0;
        if(x==201)return low;
        int to=f[x],i;
        while(to){
            i=edge[to].to;
            if(dis[i]==dis[x]+1&&(ans=dfs(i,min(low,edge[to].power)))){
                edge[to].power-=ans;//边的最大流量更新 
                edge[to^1].power+=ans;
                return ans;
            }
            to=edge[to].next;
        }
        return ans;
    }
    int main(){
        freopen("shuttle.in","r",stdin);
        freopen("shuttle.out","w",stdout);
        int n,m,x,sum=0;scanf("%d%d",&m,&n);
        for(int i=1;i<=m;i++){
            bool d=1;
            while(in(x)){
                if(d)add_edge(0,i,x),d=0,sum+=x;
                else add_edge(i,100+x,inf);
            }
            if(d)add_edge(0,i,x);
            else add_edge(i,100+x,inf);
        }
        for(int i=1;i<=n;i++){
            in(x);
            add_edge(100+i,201,x);
        }
        while(bfs()){//判断是否能到n 
                while(int tans=dfs(0,0x7fffffff))sum-=tans;//用增广路更新 
        }
        for(int i=1;i<=m;i++)if(dis[i]!=-1)printf("%d ",i);//最后t集合内的为选用的 
        printf("
    ");
        for(int i=1;i<=n;i++)if(dis[i+100]!=-1)printf("%d ",i);
        printf("
    ");
        printf("%d",sum);
        return 0;
    } 
  • 相关阅读:
    shell中的交互模式:expect
    hive(II)--sql考查的高频问题
    ETL工具--kettle篇(17.10.09更新)
    hive(I)--学习总结之常用技能
    ubantu上搭建hive环境
    shell实例练习+详解
    搭建hadoop、hdfs环境--ubuntu(完全分布式)
    oracle 获取一个字段的年月日
    oracle 两表更新 报错ORA-01779: 无法修改与非键值保存表对应的列
    oracle 查看表空间 添加数据文件
  • 原文地址:https://www.cnblogs.com/bennettz/p/6746292.html
Copyright © 2020-2023  润新知