题目地址:P2805 [NOI2009]植物大战僵尸

最大权闭合子图

若有向图 \(G\) 的子图 \(V\) 满足: \(V\) 中顶点的所有出边均指向 \(V\) 内部的顶点,则称 \(V\) 是 \(G\) 的一个闭合子图

若 \(G\) 中的点有点权,则点权和最大的闭合子图称为有向图 \(G\) 的最大权闭合子图

构图方法

建立源点 \(S\) 和汇点 \(T\) ,源点 \(S\) 连所有点权为正的点,容量为该点点权;其余点连汇点 \(T\) ,容量为该点点权的相反数,对于原图中的边 \((x,y)\) ,连边 \((x,y,+inf)\)。

定理

  • 最大权闭合图的点权和 \(=\) 所有正权点权值和 \(–\) 最小割。
  • 上述图的最小割包含 \(S\) 到不在最大权闭合图内的正权节点的边和在最大权闭合图内的负权节点到 \(T\) 的边。

推论(最大权闭合图方案)

残量网络中由源点 \(S\) 能够访问到的点,就构成一个点数最少的最大权闭合图。

本题题解

把每个植物当做一个顶点,植物携带的能源数目为顶点的权值。

如果植物 \(b\) 在植物 \(a\) 的攻击范围内,连接一条有向边 \((a,b)\) ,表示 \(a\) 可以保护 \(b\) 。

由于僵尸从右向左进攻,可以认为每个植物都被它右边相邻的植物保护,对于每个植物 \(a\) (除最左边一列),向其左边的相邻植物 \(b\) ,连接一条有向边 \((a,b)\) 。

此时可能有一些植物是互相保护的,都不能被吃掉,这样的点(和与其相连的边)应该全部删掉,拓扑排序一遍即可。

如果要吃掉一个植物,就应该把所有保护它的植物全部吃掉。

对应在图中,如果我们将图转置(即所有边转成其反向边),那么可以吃掉的植物应该构成一个闭合子图,而最优解就是最大权闭合子图。

#include <bits/stdc++.h>
using namespace std;
const int N = 1e4 + 6, M = 1e6 + 6, inf = 1e9;
int n, m, s, t, a[N], ans, d[N], deg[N], v[N];
int Head[N], Edge[M], Leng[M], Next[M], tot = 1;
queue<int> q;
vector<int> e[N];

inline void add(int x, int y, int z) {
    Edge[++tot] = y;
    Leng[tot] = z;
    Next[tot] = Head[x];
    Head[x] = tot;
}

inline bool bfs() {
    memset(d, 0, sizeof(d));
    queue<int> q;
    q.push(s);
    d[s] = 1;
    while (q.size()) {
        int x = q.front();
        q.pop();
        for (int i = Head[x]; i; i = Next[i]) {
            int y = Edge[i], z = Leng[i];
            if (deg[y] || d[y] || !z) continue;
            q.push(y);
            d[y] = d[x] + 1;
            if (y == t) return 1;
        }
    }
    return 0;
}

int dinic(int x, int flow) {
    if (x == t) return flow;
    int rest = flow;
    for (int i = Head[x]; i && rest; i = Next[i]) {
        int y = Edge[i], z = Leng[i];
        if (d[y] != d[x] + 1 || !z) continue;
        int k = dinic(y, min(rest, z));
        if (!k) d[y] = 0;
        else {
            Leng[i] -= k;
            Leng[i^1] += k;
            rest -= k;
        }
    }
    return flow - rest;
}

int main() {
    cin >> n >> m;
    s = n * m, t = s + 1;
    for (int i = 0; i < s; i++) {
        scanf("%d", &a[i]);
        int k;
        scanf("%d", &k);
        while (k--) {
            int x, y;
            scanf("%d %d", &x, &y);
            e[i].push_back(x * m + y);
            ++deg[x*m+y];
        }
    }
    for (int i = 0; i < n; i++)
        for (int j = 1; j < m; j++) {
            e[i*m+j].push_back(i * m + j - 1);
            ++deg[i*m+j-1];
        }
    for (int i = 0; i < s; i++)
        if (!deg[i]) q.push(i), v[i] = 1;
    while (q.size()) {
        int x = q.front();
        q.pop();
        for (unsigned int i = 0; i < e[x].size(); i++) {
            int y = e[x][i];
            if (!v[y] && !--deg[y]) q.push(y), v[y] = 1;
        }
    }
    for (int x = 0; x < s; x++) {
        if (!v[x]) continue;
        for (unsigned int i = 0; i < e[x].size(); i++) {
            int y = e[x][i];
            if (!v[y]) continue;
            add(y, x, inf);
            add(x, y, 0);
        }
        if (a[x] > 0) add(s, x, a[x]), add(x, s, 0), ans += a[x];
        if (a[x] < 0) add(x, t, -a[x]), add(t, x, 0);
    }
    int now = 0;
    while (bfs())
        while ((now = dinic(s, inf)))
            ans -= now;
    cout << ans << endl;
    return 0;
}

P2805 [NOI2009]植物大战僵尸的更多相关文章

  1. 图论(网络流):COGS 410. [NOI2009] 植物大战僵尸

    410. [NOI2009] 植物大战僵尸 ★★★   输入文件:pvz.in   输出文件:pvz.out   简单对比时间限制:2 s   内存限制:512 MB [问题描述] Plants vs ...

  2. COGS410. [NOI2009] 植物大战僵尸

    410. [NOI2009] 植物大战僵尸 ★★★   输入文件:pvz.in   输出文件:pvz.out   简单对比时间限制:2 s   内存限制:512 MB [问题描述] Plants vs ...

  3. BZOJ 1565: [NOI2009]植物大战僵尸

    1565: [NOI2009]植物大战僵尸 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 2317  Solved: 1071[Submit][Stat ...

  4. 【刷题】BZOJ 1565 [NOI2009]植物大战僵尸

    Description Plants vs. Zombies(PVZ)是最近十分风靡的一款小游戏.Plants(植物)和Zombies(僵尸)是游戏的主角,其中Plants防守,而Zombies进攻. ...

  5. 【bzoj1565】[NOI2009]植物大战僵尸

    1565: [NOI2009]植物大战僵尸 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 2164  Solved: 1001[Submit][Stat ...

  6. 【最大权闭合子图 tarjan】bzoj1565: [NOI2009]植物大战僵尸

    dinic+tarjan板子练手题 Description Plants vs. Zombies(PVZ)是最近十分风靡的一款小游戏.Plants(植物)和Zombies(僵尸)是游戏的主角,其 中P ...

  7. BZOJ1565: [NOI2009]植物大战僵尸

    Description Input Output 仅包含一个整数,表示可以获得的最大能源收入.注意,你也可以选择不进行任何攻击,这样能源收入为0. Sample Input 3 2 10 0 20 0 ...

  8. 【bzoj1565】 NOI2009—植物大战僵尸

    http://www.lydsy.com/JudgeOnline/problem.php?id=1565 (题目链接) 题意 给出$n*m$的棋盘,僵尸攻击每个格子可以获得$v$的分数,每个格子又会保 ...

  9. luogu2805 [NOI2009]植物大战僵尸

    想象一下,要搞掉一个植物,必须先搞掉另一些植物--我们可以发现这是一个最大权闭合子图的问题. 最大权闭合子图的话,太空飞行计划问题是一个入门题,可以一看. 然而我们手玩一下样例就会惊恐地发现,保护关系 ...

随机推荐

  1. apache thrift分析

    thrift是一个用来实现跨语言的远程调用(RPC Remote Procedure Call)的软件框架.根据接口定义语言(IDL Interface definition lanuage) 并借助 ...

  2. Druid 数据库连接池

    druid 数据库连接池 由阿里提供 步骤 1 导包 durid1.0.9 jar 包 2 定义配置文件 必须是 properties文件 名字任意 位置也任意 3 获得数据库连接池对象 通过 Dur ...

  3. day14-jdbc案例(简单的curd&分页)

    回顾: mvc jsp的设计模式1: jsp+javabean jsp的设计模式2: jsp+javabean+servlet jsp:展示数据 javabean:封装数据 封装对数据的访问 serv ...

  4. 新买苹果电脑,mac系统中小白应该了解哪些东西?

    本文旨在分享新买了mac电脑,应该做哪些设置,帮助苹果电脑小白轻松上手使用mac电脑,当然,新电脑肯定是需要安装各种软件,这里,小编推荐一下可以看看小编写的mac软件装机必备Mac 装机必备软件推荐, ...

  5. 2017-12-18python全栈9期第三天第二节之str常用操作方法及for循环之判断字母数字组成

    #!/user/bin/python# -*- coding:utf-8 -*-name = 'zd123'print(name.isalnum()) #由数字或字母组成print(name.isal ...

  6. Oracle基础--创建临时表空间/表空间/创建用户/授权

    总结:创建用户一般分四步: 第一步:创建临时表空间(创建用户之前要创建"临时表空间",若不创建则默认的临时表空间为temp.) SQL> CREATE TEMPORARY T ...

  7. Redis之Transactions(事物)

    你问我Redis支不支持事物?告诉你,Redis对事物的支持是部分支持(对比关系型数据库,没有强一致性) 定义:一个队列.一次性.顺序的.排他性的执行一系列命令 常用命令: DISCARD 取消事物, ...

  8. poi读取写入word【未完,待续】

    , [项目实战]Java POI之Word导出经典案例一 Java POI 读取word文件 POI-对于WORD的操作(一)

  9. java 中对象比较大小

    java 中对象比较大小 java 中对象比较大小有两种方法 1:实现Comparable 接口 的 public int compareTo(T o) 方法: 2:实现Comparator 接口 的 ...

  10. [Android] Android Studio 修改Gradle使用国内源

    Gradle 仓库中心的项目,下载速度又比较慢, 网上查询了下, 使用阿里云的Maven镜像仓库 在 project 的 build.gradle中修改如下: allprojects { reposi ...