「NOI2009」植物大战僵尸

传送门

这是一道经典的最大权闭合子图问题,可以用最小割解决(不会的可以先自学一下)

具体来说,对于这道题,我们对于两个位置的植物 \(i\) 和 \(j\) ,如果 \(j\) 可以保护 \(i\) ,也就是 \(i\) 在 \(j\) 的攻击范围内(特别的,我们认为一个植物也会被它右边的第一个植物保护),我们就连边 \(i \to j\),因为攻击一个植物的前提就是攻击掉所有保护它的植物,我们这样连边恰好可以满足闭合子图的性质。

但是我们还会碰到一个问题,那就是互相保护的情况,在图上也就是环的情况,我们发现一个环是不可能被攻击的,所以说我们只把没有位于环上的点用来建图,具体可以用反图+拓扑排序实现。

这样就解决了。

参考代码:

#include <cstring>
#include <cstdio>
#define rg register
#define file(x) freopen(x".in", "r", stdin), freopen(x".out", "w", stdout)
template < class T > inline T min(T a, T b) { return a < b ? a : b; }
template < class T > inline void read(T& s) {
s = 0; int f = 0; char c = getchar();
while ('0' > c || c > '9') f |= c == '-', c = getchar();
while ('0' <= c && c <= '9') s = s * 10 + c - 48, c = getchar();
s = f ? -s : s;
} const int _ = 605, __ = 400005, INF = 2147483647; int tot = 1, head[_]; struct Edge { int ver, cap, nxt; } edge[__ << 1];
inline void Add_edge(int u, int v, int d) { edge[++tot] = (Edge) { v, d, head[u] }, head[u] = tot; }
inline void link(int u, int v, int d) { Add_edge(u, v, d), Add_edge(v, u, 0); } int n, m, a[_], able[_], dgr[_];
int s, t, dep[_], cur[_];
int num; struct node { int u, v; } p[__];
int hd, tl, Q[_]; inline int id(int i, int j) { return (i - 1) * m + j; } inline int bfs() {
memset(dep, 0, sizeof (int) * (t - s + 1));
hd = tl = 0;
Q[++tl] = s, dep[s] = 1;
while (hd < tl) {
int u = Q[++hd];
for (rg int i = head[u]; i; i = edge[i].nxt) {
int v = edge[i].ver;
if (dep[v] == 0 && edge[i].cap > 0)
dep[v] = dep[u] + 1, Q[++tl] = v;
}
}
return dep[t] > 0;
} inline int dfs(int u, int flow) {
if (u == t) return flow;
for (rg int &i = cur[u]; i; i = edge[i].nxt) {
int v = edge[i].ver;
if (dep[v] == dep[u] + 1 && edge[i].cap > 0) {
int res = dfs(v, min(flow, edge[i].cap));
if (res) { edge[i].cap -= res, edge[i ^ 1].cap += res; return res; }
}
}
return 0;
} inline int Dinic() {
int res = 0;
while (bfs()) {
for (rg int i = s; i <= t; ++i) cur[i] = head[i];
while (int d = dfs(s, INF)) res += d;
}
return res;
} inline void toposort() {
tot = 0, memset(head, 0, sizeof head);
for (rg int i = 1; i <= num; ++i) Add_edge(p[i].u, p[i].v, 0), ++dgr[p[i].v];
hd = tl = 0;
for (rg int i = 1; i <= n * m; ++i) if (dgr[i] == 0) Q[++tl] = i;
while (hd < tl) {
int u = Q[++hd]; able[u] = 1;
for (rg int i = head[u]; i; i = edge[i].nxt) if (!--dgr[edge[i].ver]) Q[++tl] = edge[i].ver;
}
} int main() {
#ifndef ONLINE_JUDGE
file("cpp");
#endif
read(n), read(m), s = 0, t = n * m + 1;
for (rg int w, x, y, i = 1; i <= n; ++i)
for (rg int j = 1; j <= m; ++j) {
read(a[id(i, j)]), read(w);
while (w--) read(x), read(y), ++x, ++y, p[++num] = (node) { id(i, j), id(x, y) };
}
for (rg int i = 1; i <= n; ++i)
for (rg int j = 1; j < m; ++j) p[++num] = (node) { id(i, j + 1), id(i, j) };
toposort();
tot = 1, memset(head, 0, sizeof head);
for (rg int i = 1; i <= num; ++i) {
int u = p[i].u, v = p[i].v;
if (!able[u] || !able[v]) continue ;
link(v, u, INF);
}
int sum = 0;
for (rg int i = 1; i <= n * m; ++i) {
if (!able[i]) continue ;
if (a[i] > 0) link(s, i, a[i]), sum += a[i];
if (a[i] < 0) link(i, t, -a[i]);
}
printf("%d\n", sum - Dinic());
return 0;
}

「NOI2009」植物大战僵尸的更多相关文章

  1. 【BZOJ1565】【NOI2009】植物大战僵尸

    好久没写博客了 题目 题目在这里 思路&做法 没什么好说的 应该很容易看出是 最大闭合子图 吧? 不过要注意一下的是,这题 可能有植物是不可能被击溃的 , 所以要先跑一遍 拓扑排序 把这些点排 ...

  2. [Android] 转移“植物大战僵尸2”存档的办法,无需root

    作者:zyl910 查过了很多文章,都说需要root后才能转移存档.但很多时候是不能root的,此时该怎么办呢? 我研究了很久,最终找到了一种办法,无需root也能转移存档. 一.备份 我用的是联想手 ...

  3. 32位汇编第六讲,OllyDbg逆向植物大战僵尸,快速定位阳光基址

    32位汇编第六讲,OllyDbg逆向植物大战僵尸,快速定位阳光基址 一丶基址,随机基址的理解 首先,全局变量的地址,我们都知道是固定的,是在PE文件中有保存的 但是高版本有了随机基址,那么要怎么解决这 ...

  4. 原生JS实现的h5小游戏-植物大战僵尸

    代码地址如下:http://www.demodashi.com/demo/12755.html 项目介绍 本项目是利用原生js实现的h5小游戏-植物大战僵尸,主要结合了一下自己对于h5小游戏的理解,结 ...

  5. 植物大战僵尸:寻找阳光掉落Call调用

    实验目标:通过遍历阳光产生的时间,寻找阳光产生的本地Call,使用代码注入器注入,自定义生成阳光 阳光CALL遍历技巧: 进入植物大战僵尸-> 当出现阳光后->马上搜索未知初始数值 返回游 ...

  6. java小项目之:植物大战僵尸,这个僵尸有点冷!内附素材源码

    Java小项目之:植物大战僵尸! <植物大战僵尸>是由PopCap Games开发的一款益智策略类单机游戏,于2009年5月5日发售,这款游戏可谓是无人不知无人不晓. 在我身边,上到40岁 ...

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

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

  8. P2805 [NOI2009]植物大战僵尸

    题目地址:P2805 [NOI2009]植物大战僵尸 最大权闭合子图 若有向图 \(G\) 的子图 \(V\) 满足: \(V\) 中顶点的所有出边均指向 \(V\) 内部的顶点,则称 \(V\) 是 ...

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

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

随机推荐

  1. 普及C组第二题(8.5)

    1565. [GDKOI]神秘山庄 (Standard IO) 时间限制: 1000 ms  空间限制: 262144 KB 题目: 翠亨村是一个神秘的山庄,并不是因为它孕育了伟人孙中山,更神秘的是山 ...

  2. python evel()的用法

    老生常谈部分: eval(expression[, globals[, locals]]) expression -- 表达式. globals -- 变量作用域,全局命名空间,如果被提供,则必须是一 ...

  3. IDEA导入Git项目后无Git选项

  4. 前端开发:mock.js的简单应用(生成随机数据,拦截 Ajax 请求)

    摘要 在前端开发过程中,后端接口还没有完全开发完成时,前端开发人员就需要学会自己模拟后端接口数据,更快更好的完成开发任务.模拟后端接口数据的js库有很多,今天就简单就简单的分享下mock.js在前端开 ...

  5. python-用正则表达式筛选文本信息

    [摘要]  本文主要介绍如何对多个文本进行读取,并采用正则表达式对其中的信息进行筛选,将筛选出来的信息存写到一个新文本. 打开文件:open(‘文件名’,‘打开方式’)>>>file ...

  6. GitBook的账号注册和安装使用(一)

    1.GitBook账号注册 GitBook原注册地址  https://legacy.gitbook.com/join 改为: https://www.gitbook.com/ (1)注册账号:htt ...

  7. 连接(JOIN)

    join 用于把来自两个或多个表的行结合起来,基于这些表之间的共同字段. INNER JOIN 从多个表中返回满足 JOIN 条件的所有行. INNER JOIN:如果表中有至少一个匹配,则返回行 L ...

  8. 数据库中的null,踩坑笔记

    问题来源:查询表中,complete_type 不为2的数据. 我的想法:select * from 表名 where complete_type != '2'  (除了第2条,全部显示,没问题呀) ...

  9. java编译器不匹配问题(java compiler level does not match the version of the installed java project facet)

    问题:项目经常copy过来,经常会报说Java编译器不匹配 解决方法:找到项目所在的目录,在.settings子目录里面,用文本编辑器打开org.eclipse.wst.common.project. ...

  10. 【C语言】计算N名同学的某门功课的平均成绩

    分析: 循环输入number只童鞋的成绩,累加为sum,最后输出sum/number即可! 代码: #include<stdio.h> int main() { , score;//sco ...