题目地址: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. 2017-12-15python全栈9期第二天第三节之作业讲解用户三次登陆

    #!/user/bin/python# -*- coding:utf-8 -*-i = 0while i < 3: username = input('请输入账号:') password = i ...

  2. weblogic每天日志合并shell脚本 [个人记录]【转】【补】

    from RogerZhu modified by King sh logback.rb "/data/logs/" "/tmp/domain" "a ...

  3. 【1】【leetcode-93】复原IP地址

    (不会,典型) 给定一个只包含数字的字符串,复原它并返回所有可能的 IP 地址格式. 示例: 输入: "25525511135" 输出: ["255.255.11.135 ...

  4. vue中computed和watch

    computed 计算属性 能够监听vue数据上的变化,页面上来就执行一次,每改变一次数据就又触发.在操作数据的时候,会派生出另一个事情 1.函数形式 computed:{ listenArr(){ ...

  5. MySQL忘记root密码的解决办法

    # 1.停掉MySQL进程 [root@standby ~]# /etc/init.d/mysqld stop Shutting down MySQL... SUCCESS! [root@standb ...

  6. yum方式安装mysql

    安装步骤 1. 安装yum仓库 到https://dev.mysql.com/downloads/repo/yum/ 下载对应操作系统版本的yum仓库,然后进行安装:sudo rpm -Uvh pla ...

  7. 数据结构Java实现01----线性表与顺序表

    一.线性结构: 如果一个数据元素序列满足: (1)除第一个和最后一个数据元素外,每个数据元素只有一个前驱数据元素和一个后继数据元素: (2)第一个数据元素没有前驱数据元素: (3)最后一个数据元素没有 ...

  8. Uncaught TypeError: $(…).orgcharts is not a function

    调整js顺序没有解决,最后增加NoConflict解决,注意红色部分 function initorgcharts() { var $jq = jQuery.noConflict(true); org ...

  9. SSH整合方案二(不带hibernate.cfg.xml)

    整体结构: 1.引入相关jar包 2.编写实体类和映射文件 package cn.zqr.domain; public class Customer { private Long cust_id; p ...

  10. Maven的日常

    强烈建议把 Maven 的 settings.xml 文件同时放在:%USER_HOME%/.m2/settings.xml 和${maven.home}/conf/settings.xml 两个地方 ...