Description

Input

Output

  仅包含一个整数,表示可以获得的最大能源收入。注意,你也可以选择不进行任何攻击,这样能源收入为0。

Sample Input

  3 2
  10 0
  20 0
  -10 0
  -5 1 0 0
  100 1 2 1
  100 0

Sample Output

  25
 

Solution

  按照依赖关系建立有向图:若清除$a$前必须清除$b$,则连边$a$至$b$。这些依赖关系包括同行植物左边对右边的依赖,以及被保护者对保护者的依赖。

  首先不能考虑开挂集团,也就是依赖关系成强联通分量的植物,也包括能通过依赖关系走到强联通分量的植物——它们都无敌,需要排除掉。这可以用tarjan加上反向边的深搜预处理。

  

  一个植物能够下手,当且仅当其出度为0.

  每一株植物又是带正负权值的,那么明显是要在依赖图中,求一个最大权闭合子图。也就是要有植物起手(迎合闭合的性质,出边都在闭合子图内,即依赖的植物都要一起干掉,都应该在闭合子图的范围内),且干掉的植物权值和最大。

  按照最大权闭合子图的建立方法:源点向所有正权点连容量为其权值的边,所有负权点向汇点连容量为其权值绝对值的边;所有节点按依赖关系连边,容量为$+\infty$。

  答案是所有正权点点权值和减去最大流。能将负权转化为正权来跑网络流的原因,拆拆括号就可以发现,这是很巧妙的。


#include <cstdio>
#include <queue>
#include <vector>
using namespace std;
const int N=,INF=;
int n,m,a[N],h[N],hr[N],tot;
int dfn[N],low[N],tmcnt,is[N],st[N],top,ins[N],vis[N];
int S,T,dis[N],cur[N];
int sum;
queue<int> q;
vector<int> list[N];
struct Edge{int v,f,next;}g[];
inline int min(int x,int y){return x<y?x:y;}
inline int id(int x,int y){return (x-)*m+y;}
inline void addEdge(int u,int v){
g[++tot].v=v; g[tot].next=h[u]; h[u]=tot;
g[++tot].v=u; g[tot].next=hr[v]; hr[v]=tot;
}
inline void addEdge(int u,int v,int f){
g[++tot].v=v; g[tot].f=f; g[tot].next=h[u]; h[u]=tot;
g[++tot].v=u; g[tot].f=; g[tot].next=h[v]; h[v]=tot;
}
bool bfs(){
while(!q.empty()) q.pop();
q.push(S);
for(int i=;i<=T;i++) dis[i]=-;
dis[S]=;
while(!q.empty()){
int u=q.front(); q.pop();
for(int i=h[u],v;i;i=g[i].next)
if(g[i].f&&dis[v=g[i].v]==-){
dis[v]=dis[u]+;
if(v==T) return true;
q.push(v);
}
}
return dis[T]!=-;
}
int dfs(int u,int delta){
if(u==T) return delta;
int ret=,get;
for(int i=cur[u],v;i&&delta;i=g[i].next)
if(g[i].f&&dis[v=g[i].v]==dis[u]+){
get=dfs(v,min(delta,g[i].f));
g[i].f-=get; g[i^].f+=get;
if(g[i].f) cur[u]=i;
delta-=get; ret+=get;
}
if(!ret) dis[u]=-;
return ret;
}
int dinic(){
int ret=;
while(bfs()){
for(int i=;i<=T;i++) cur[i]=h[i];
ret+=dfs(S,INF);
}
return ret;
}
void tarjan(int u,int fa){
dfn[u]=low[u]=++tmcnt;
st[++top]=u; ins[u]=;
for(int i=h[u],v;i;i=g[i].next){
v=g[i].v;
if(!dfn[v]){
tarjan(v,u);
low[u]=min(low[u],low[v]);
}
else if(ins[v])
low[u]=min(low[u],dfn[v]);
}
if(low[u]==dfn[u]){
if(st[top]==u){
ins[u]=;
top--;
return;
}
int x;
do{
x=st[top--];
ins[x]=;
is[x]=;
}while(x!=u);
}
}
void clear(int u){
vis[u]=; is[u]=;
for(int i=hr[u],v;i;i=g[i].next)
if(!vis[v=g[i].v])
clear(v);
}
int main(){
freopen("input.in","r",stdin);
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)
for(int j=;j<=m;j++){
int k=id(i,j),l,x,y;
scanf("%d%d",&a[k],&l);
while(l--){
scanf("%d%d",&x,&y);
addEdge(id(x+,y+),k);
list[id(x+,y+)].push_back(k);
}
}
for(int i=;i<=n;i++)
for(int j=;j<m;j++)
addEdge(id(i,j),id(i,j+));
for(int i=,up=n*m;i<=up;i++)
if(!dfn[i])
tarjan(i,);
for(int i=,up=n*m;i<=up;i++)
if(!vis[i]&&is[i])
clear(i);
for(int i=,up=n*m;i<=up;i++) h[i]=;
tot=;
S=n*m+; T=n*m+;
for(int i=;i<=n;i++)
for(int j=;j<=m;j++){
int x=id(i,j);
if(j<m&&!is[x]&&!is[id(i,j+)])
addEdge(x,id(i,j+),INF);
if(is[x]) continue;
if(a[x]>=){
addEdge(S,x,a[x]);
sum+=a[x];
}
else addEdge(x,T,-a[x]);
int sz=list[x].size();
for(int k=;k<sz;k++)
addEdge(x,list[x][k],INF);
}
int maxflow=dinic();
printf("%d\n",sum-maxflow);
return ;
}

奇妙代码

  

【BZOJ1565】 植物大战僵尸的更多相关文章

  1. BZOJ1565 植物大战僵尸

    AC通道:http://www.lydsy.com/JudgeOnline/problem.php?id=1565 这题看上去并不会做,结果又是最大权闭合子图的裸题. 于是就去看了一发论文,明白建图的 ...

  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. 【bzoj1565】 NOI2009—植物大战僵尸

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

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

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

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

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

随机推荐

  1. IO (二)

    1 字符流的缓冲区 缓冲区的出现提高了对数据的读写效率. 对应的类: BufferedWriter BufferedReader 缓冲区要结合流才能使用. 在流的基础上对流的功能进行了增强. 2 Bu ...

  2. java IO(一):File类

    */ .hljs { display: block; overflow-x: auto; padding: 0.5em; color: #333; background: #f8f8f8; } .hl ...

  3. javascript:将URL的参数列表解析为一个对象

    <!doctype html> <html> <head> <meta charset="utf-8"> <title> ...

  4. js中的深拷贝与浅拷贝

    对象的深拷贝于浅拷贝 对于基本类型,浅拷贝过程就是对值的复制,这个过程会开辟出一个新的内存空间,将值复制到新的内存空间.而对于引用类型来书,浅拷贝过程就是对指针的复制,这个过程并没有开辟新的堆内存空间 ...

  5. linux修改TCP最大连接数

    环境 操作系统: oracle-linux7.3 修改系统支持的最大TCP连接 最大tcp连接数和系统允许打开的最大文件数,用户允许打开的最大文件数,TCP网络连接可用的端口范围有关,取上述的最小值: ...

  6. c# 类属性和方法

    属性 public 类字段 就相当于c#里面暴露给外面的属性 类似nodejs的 module.exports 但是属性又不同于普通的字段,属性只是外部包装字段 没有自己的任何含量 类似退换后的方法. ...

  7. 15_Python函数名本质

    函数名的本质 函数名实质上就是函数的内存地址 def wrapper(): pass print(wrapper) 1.引用是什么? 当我们定义a=1的时候,系统会开辟一块内存空间来保存1,然后用a变 ...

  8. ABP官方文档翻译 3.2 值对象

    值对象 介绍 值对象基类 最佳实践 介绍 "展现领域描述性层面且没有概念性身份的对象称之为值对象."(Eric Evans). 和实体相反,实体有身份标示(Id),值对象没有身份标 ...

  9. 使用mongoose和bcrypt实现用户密码加密

    前面的话 最近在做的个人项目中,需要对密码进行加密保存,对该操作的详细步骤记录如下 介绍 关于mongoose已经写过博客就不再赘述,下面主要介绍bcrypt bcrypt是一个由两个外国人根据Blo ...

  10. JetBrains Pycharm 破解+汉化

    准备材料: 1.JetBrains Pycharm    传送门:  https://pan.baidu.com/s/1qZCpIR6 密码: rvrn 2.JetbrainsCrack-2.6.2. ...