【最大权闭合子图/最小割】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向每个i连一条容量为ai的边,T向每个i连一条容量为bi的边。显然答案=总的容量之和-最小割。

那么如果有了组合方案呢?

对于每一个方案,我们可以拆为两个点u和v,由S向u连一条容量为c1i的边;由v向T连一条容量为c2i的边。然后由S向组合里的每一个点连一条容量为INF的边,由组合里的每一个点向T连一条容量为INF的边。显然割边必定会是和与S或者T相连接的点。

可能这里会有一个疑惑:如果一个集合中的点的割边在和S相连的点中,而u,v的割边在和T相连的点中(也就是说我们把农作物种在了A中,却算了收益在B中。)

事实上是——不可能的。我们可以证明:u、v和它们组合中的割边一定同时和S或者T连,否则必定有一条S到T的通路,就无法形成割了!

所以最后答案=总的容量之和-最小割

画画图就明白了:)

...T了,不知道为什么。

删掉了STL部分。还是T了。我要静静。

/*还是TLE,回头看*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define S 0
#define T MAXN-1
using namespace std;
const int INF=0x7fffffff;
const int MAXN=3000+50;
const int MAXM=4004000+50;
struct node
{
    int fr,to,pos,cap;
};
int n,m,sum;
int dis[MAXN];
int vis[MAXN];
int cur[MAXN];
int first[MAXN],next[MAXM];
node edge[MAXM];
int tot=0;

int read() {
    int x = 0;
    char ch = getchar();
    while (ch < ‘0‘ || ‘9‘ < ch)
        ch = getchar();
    while (‘0‘ <= ch && ch <= ‘9‘) {
        x = x * 10 + ch - ‘0‘;
        ch = getchar();
    }
    return x;
}

void addedge(int u,int v,int c)
{
    edge[++tot]=(node){u,v,tot+1,c};
    next[tot]=first[u];first[u]=tot;
    edge[++tot]=(node){u,v,tot-1,0};
    next[tot]=first[v];first[v]=tot;
}

void build()
{
    memset(first,-1,sizeof(first));
    memset(next,-1,sizeof(next));
    int ai,bi;
    n=read();
    for (int i=1;i<=n;i++)
    {
        ai=read();
        sum+=ai;
        addedge(S,i,ai);
    }
    for (int i=1;i<=n;i++)
    {
        bi=read();
        sum+=bi;
        addedge(i,T,bi);
    }
    m=read();
    int k,c1i,c2i;
    for (int i=1;i<=m;i++)
    {
        k=read();c1i=read();c2i=read();
        int u=n+i;
        int v=n+i+m;
        addedge(S,u,c1i);
        addedge(v,T,c2i);
        sum+=c1i+c2i;
        for (int j=1;j<=k;j++)
        {
            int ci;
            ci=read();
            addedge(u,ci,INF);
            addedge(ci,v,INF);
        }
    }
}

int bfs()
{
    memset(dis,-1,sizeof(dis));
    int l=0,r=0;
    int que[MAXN];
    que[++r]=S;
    dis[S]=0;

    while (l<r)
    {
        int head=que[l];l++;
        for (int i=first[head];i!=-1;i=next[i])
        {
            node &tmp=edge[i];
            if (dis[tmp.to]==-1 && tmp.cap>0)
            {
                dis[tmp.to]=dis[head]+1;
                que[++r]=tmp.to;
            }
        }
    }
    return (dis[T]!=-1);
}

int dfs(int s,int t,int f)
{
    vis[s]=1;
    if (s==t || !f) return f;
    int res=0;
    for (int i=first[s];i!=-1;i=next[i])
    {
        node &tmp=edge[i];
        if (!vis[tmp.to] && tmp.cap>0 && dis[tmp.to]==dis[s]+1)
        {
            int delta=dfs(tmp.to,t,min(tmp.cap,f));
            if (delta>0)
            {
                tmp.cap-=delta;
                edge[tmp.pos].cap+=delta;
                f-=delta;
                res+=delta;
                if (!f) return res;
            }
        }
    }
    return res;
}

int dinic()
{
    int flow=0;
    while (bfs())
    {
        memset(vis,0,sizeof(vis));
        flow+=dfs(S,T,INF);
    }
    return flow;
}

int main()
{
    build();
    printf("%d\n",sum-dinic());
    return 0;
}
时间: 2024-08-02 08:39:02

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

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

最大权闭合子图(最大流最小割) •参考资料 [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

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

引入闭合子图的概念 : 通俗点说就是选出一个图的子图,使得子图中的所有点出度指向的点依旧在这个子图内,则说明此子图是闭合子图. 最大权闭合子图 : 假设每个点具有点权值,在一个图的所有闭合子图中,点权之和最大的即是最大权闭合子图. 求取最大权闭合子图的权值之和是有一个结论的 一.先抽象出一个超级源.汇点 二.将权值为正的点和超级源点连接.容量为权值 三.将权值为负的点和超级汇点连接.容量为权值的绝对值 四.然后除了源.汇之外的点原本怎么连泽怎么连.且容量为无穷大 五.最大权闭合子图权值  =  

最大权闭合图 最小割

闭合图为原图的一个子图, 满足任意一个节点的后继仍在闭合图中. 给原图的每个点以一个点权, 权值总和最大的闭合图称为最大权闭合图. 我们考虑利用最小割求解最大权闭合图. 首先, 为了权值最大, 我们贪心地将所有点权为正的点给选上, 但是这样可能会矛盾, 因为一个点权为正的点的后继可能点权为负. 我们考虑利用最小割, 减去最小的使方案合法的花费. 建立源点 S , 与 S 相连的意义是这个点被选择, 则初始的时候, 对于点权为正的点 i , 连边 (S, i, a[i]) . 建立汇点 T , 与

[luoguP2762] 太空飞行计划问题(最大权闭合图—最小割—最大流)

传送门 如果将每一个实验和其所对的仪器连一条有向边,那么原图就是一个dag图(有向无环) 每一个点都有一个点权,实验为收益(正数),仪器为花费(负数). 那么接下来可以引出闭合图的概念了. 闭合图是原图的一个点集,其中这个点集中每个点的出边所指向的点依然在这个点集中,那么这个点集就是个闭合图. 比如论文中的这个图: 在图 3.1 中的网络有 9 个闭合图(含空集):∅,{3,4,5},{4,5},{5},{2,4,5},{2,5},{2,3,4,5},{1,2,4,5},{1,2,3,4,5}

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]每个人都为公司带来一个收益,公司老板要裁员(当然是业绩不好给公司带来负收益的人被裁掉啦~),然而踢走一个人会把他的下属都踢走,求最大收益 最大权闭合子图~,其实就是最小割啦,此题要求最小化走的人数,然而就是最小割中的人数QAQ(并不知道为什么),dfs(S)相关的点 #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include