最大权闭合子图 ( 最大流最小割模型 )

引入闭合子图的概念 : 通俗点说就是选出一个图的子图,使得子图中的所有点出度指向的点依旧在这个子图内,则说明此子图是闭合子图。

最大权闭合子图 : 假设每个点具有点权值,在一个图的所有闭合子图中,点权之和最大的即是最大权闭合子图。

求取最大权闭合子图的权值之和是有一个结论的

一、先抽象出一个超级源、汇点

二、将权值为正的点和超级源点连接、容量为权值

三、将权值为负的点和超级汇点连接、容量为权值的绝对值

四、然后除了源、汇之外的点原本怎么连泽怎么连、且容量为无穷大

五、最大权闭合子图权值  =  所有权值为正的权值之和  -  最大流

至于原理给出两个链接、解释的不错 ==> 链接I链接II

一些题目

BZOJ 1497 最大获利

分析 : 如果要选择一个带有收益的边作为收益的话,那么就要同时选择其两个端点,如果将边抽象出来化成一个点的话,那么就是要选择一些点且这些

点要构成闭合子图,所以就是求取最大权闭合子图,那么就将每条边抽象成一个点,在处理每个边的信息的时候 (u, v, w) ,连接源点和这条边的化成的

点连接容量为 w ,然后从这个边化成的点连向 u、v 容量为 INF,构成限制关系,即选择这个边化成的点就必须同时选择 u 和 v,最后将所有的点和汇

点连接,权值是点权的绝对值

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
const int INF = 0x3f3f3f3f;

struct Edge
{
    int from,to,cap,flow;
    Edge(){}
    Edge(int from,int to,int cap,int flow):from(from),to(to),cap(cap),flow(flow){}
};

struct Dinic
{
    int n,m,s,t;            //结点数,边数(包括反向弧),源点与汇点编号
    vector<Edge> edges;     //边表 edges[e]和edges[e^1]互为反向弧
    vector<int> G[maxn];    //邻接表,G[i][j]表示结点i的第j条边在e数组中的序号
    bool vis[maxn];         //BFS使用,标记一个节点是否被遍历过
    int d[maxn];            //d[i]表从起点s到i点的距离(层次)
    int cur[maxn];          //cur[i]表当前正访问i节点的第cur[i]条弧

    void init(int n,int s,int t)
    {
        this->n=n,this->s=s,this->t=t;
        for(int i=0;i<=n;i++) G[i].clear();
        edges.clear();
    }

    void AddEdge(int from,int to,int cap)
    {
        edges.push_back( Edge(from,to,cap,0) );
        edges.push_back( Edge(to,from,0,0) );
        m = edges.size();
        G[from].push_back(m-2);
        G[to].push_back(m-1);
    }

    bool BFS()
    {
        memset(vis,0,sizeof(vis));
        queue<int> Q;//用来保存节点编号的
        Q.push(s);
        d[s]=0;
        vis[s]=true;
        while(!Q.empty())
        {
            int x=Q.front(); Q.pop();
            for(int i=0; i<G[x].size(); i++)
            {
                Edge& e=edges[G[x][i]];
                if(!vis[e.to] && e.cap>e.flow)
                {
                    vis[e.to]=true;
                    d[e.to] = d[x]+1;
                    Q.push(e.to);
                }
            }
        }
        return vis[t];
    }

    //a表示从s到x目前为止所有弧的最小残量
    //flow表示从x到t的最小残量
    int DFS(int x,int a)
    {
        if(x==t || a==0)return a;
        int flow=0,f;//flow用来记录从x到t的最小残量
        for(int& i=cur[x]; i<G[x].size(); i++)
        {
            Edge& e=edges[G[x][i]];
            if(d[x]+1==d[e.to] && (f=DFS( e.to,min(a,e.cap-e.flow) ) )>0 )
            {
                e.flow +=f;
                edges[G[x][i]^1].flow -=f;
                flow += f;
                a -= f;
                if(a==0) break;
            }
        }
        if(!flow) d[x] = -1;///炸点优化
        return flow;
    }

    int Maxflow()
    {
        int flow=0;
        while(BFS())
        {
            memset(cur,0,sizeof(cur));
            flow += DFS(s,INF);
        }
        return flow;
    }
}DC;

int main(void)
{
    int N, M;
    scanf("%d %d", &N, &M);

    int S = 0;
    int T = N+M+1;

    DC.init(N+M+2, S, T);

    for(int i=1; i<=N; i++){
        int Cost;
        scanf("%d", &Cost);
        DC.AddEdge(i, T, Cost);
    }

    int tot = 0;

    for(int i=1; i<=M; i++){
        int u, v, w;
        scanf("%d %d %d", &u, &v, &w);
        DC.AddEdge(S, N+i, w);
        DC.AddEdge(N+i, u, INF);
        DC.AddEdge(N+i, v, INF);
        tot += w;
    }

    printf("%d\n", tot - DC.Maxflow());

    return 0;
}

原文地址:https://www.cnblogs.com/Rubbishes/p/9211173.html

时间: 2024-07-29 21:12:16

最大权闭合子图 ( 最大流最小割模型 )的相关文章

最大权闭合子图(最小割)

最大权闭合子图(最大流最小割) •参考资料 [1]最大权闭合子图 •权闭合子图 存在一个图的子图,使得子图中的所有点出度指向的点依旧在这个子图内,则此子图是闭合子图. 在这个图中有8个闭合子图:∅,{3},{4},{2,4},{3,4},{1,3,4},{2,3,4},{1,2,3,4} •最大权闭合子图 在一个图中每个点具有点权值,在他的所有闭合子途中点权之和最大的即是最大权闭合子图. •详解 最大权闭合子图 结论 最大权闭合子图权值  =  所有权值为正的权值之和  -  最大流 •步骤 建

bzoj 1497 [NOI2006]最大获利【最大权闭合子图+最小割】

不要被5s时限和50000点数吓倒!大胆网络流!我一个5w级别的dinic只跑了1s+! 看起来没有最大权闭合子图的特征--限制,实际上还是有的. 我们需要把中转站看成负权点,把p看成点权,把客户看成正权点,把c看成点权,然后把中转站点a.b作为客户点的依赖点 s点向所有正权点连边,流量为点权:所有负权点向t连边,流量为负点权(即正数!) 对于所有有依赖关系的点,由客户点向中转站点连边,流量为inf,也就是最大权闭合子图中的向其依赖点连边 连边的意义详见:http://www.cnblogs.c

【最大权闭合子图/最小割】BZOJ3438-小M的作物【待填】

[题目大意] 小M在MC里开辟了两块巨大的耕地A和B(你可以认为容量是无穷),现在,小P有n中作物的种子,每种作物的种子有1个(就是可以种一棵作物)(用1...n编号),现在,第i种作物种植在A中种植可以获得ai的收益,在B中种植可以获得bi的收益,而且有m种作物组合,第i个组合中的作物共同种在A中可以获得c1i的额外收益,共同总在B中可以获得c2i的额外收益,所以,小M很快地算出了种植的最大收益. [思路] 首先,如果没有组合方案应该怎么做呢?其实非常方便. 首先建立超级源点S和超级汇点T,S

hiho一下 第119周 #1398 : 网络流五&#183;最大权闭合子图 【最小割-最大流--Ford-Fulkerson 与 Dinic 算法】

#1398 : 网络流五·最大权闭合子图 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 周末,小Hi和小Ho所在的班级决定举行一些班级建设活动. 根据周内的调查结果,小Hi和小Ho一共列出了N项不同的活动(编号1..N),第i项活动能够产生a[i]的活跃值. 班级一共有M名学生(编号1..M),邀请编号为i的同学来参加班级建设活动需要消耗b[i]的活跃值. 每项活动都需要某些学生在场才能够进行,若其中有任意一个学生没有被邀请,这项活动就没有办法进行. 班级建设的活

BZOJ1565 NOI 2009 植物大战僵尸 topo+最小割(最大权闭合子图)

题目链接:https://www.luogu.org/problemnew/show/P2805(bzoj那个实在是有点小小的辣眼睛...我就把洛谷的丢出来吧...) 题意概述:给出一张有向图,这张有向图上的每个点都有一个点权,想要访问某个点必须要先访问这个点所能够访问(遍历)到的所有点,在访问到一个点之后将会得到这个点的权值(可正可负).问访问这张图可以得到的最大点权和. 原题说过来说过去实际上是描述了一个植物之间的保护关系,也就是说明了植物之间的先后访问顺序之间的关系.可以描述为要"要访问点

网络流——最小割求最大权闭合子图

定义 有一个有向图,每一个点都有一个权值(可以为正或负或0),选择一个权值和最大的子图,使得每个点的后继都在子图里面,这个子图就叫最大权闭合子图. 如下图:  能选的子图有?,{4},{3,4},{2,4},{1,2,3,4},它们的权值分别为0,-1,5,-6,4. 所以最大权闭合子图为{3,4},权值为5. 解法 这个问题可以转化为最小割问题,用网络流解决. 从源点s向每个正权点连一条容量为权值的边,每个负权点向汇点t连一条容量为权值的绝对值的边,有向图原来的边容量全部为无限大.  求它的最

POJ 2987 - Firing (最大权闭合子图)

题意:求一个图的最大权闭合子图 教科书:https://blog.csdn.net/can919/article/details/77603353 最小割模型的应用,源点向正权点建容量为该权值的弧;负权点向汇点建容量为该权值绝对值的弧;有偏序关系的点对之间建容量为正无穷的弧. 跑出最大流,根据最大流最小割定理:最大流的值即最小割.所求最大闭合子图的值为|正权点权值之和| - |最小割|. 此外,还要求删去人的数目.那么从源点出发,且不是最小割的边,就是被选择的边. 所以从源点dfs,若遇到容量不

HDU5772 String problem(最大权闭合子图)

题目..说了很多东西 官方题解是这么说的: 首先将点分为3类 第一类:Pij 表示第i个点和第j个点组合的点,那么Pij的权值等于w[i][j]+w[j][i](表示得分) 第二类:原串中的n个点每个点拆出一个点,第i个点权值为 –a[s[i]] (表示要花费) 第三类:对于10种字符拆出10个点,每个点的权值为  -(b[x]-a[x]) 那么我们可以得到一个关系图 ,对于第一类中的点Pij,如果想要选择Pij,你就必须要选中第二类中的点i和j,对于第二类中的点如果你想选中第i个点,其对应的字

HDU5855 Less Time, More profit(最大权闭合子图)

题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=5855 Description The city planners plan to build N plants in the city which has M shops. Each shop needs products from some plants to make profit of proi units. Building ith plant needs investment o