【BZOJ1565】 植物大战僵尸
Description
Input
Output
仅包含一个整数,表示可以获得的最大能源收入。注意,你也可以选择不进行任何攻击,这样能源收入为0。
Sample Input
10 0
20 0
-10 0
-5 1 0 0
100 1 2 1
100 0
Sample Output
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&δ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】 植物大战僵尸的更多相关文章
- BZOJ1565 植物大战僵尸
AC通道:http://www.lydsy.com/JudgeOnline/problem.php?id=1565 这题看上去并不会做,结果又是最大权闭合子图的裸题. 于是就去看了一发论文,明白建图的 ...
- [Android] 转移“植物大战僵尸2”存档的办法,无需root
作者:zyl910 查过了很多文章,都说需要root后才能转移存档.但很多时候是不能root的,此时该怎么办呢? 我研究了很久,最终找到了一种办法,无需root也能转移存档. 一.备份 我用的是联想手 ...
- 32位汇编第六讲,OllyDbg逆向植物大战僵尸,快速定位阳光基址
32位汇编第六讲,OllyDbg逆向植物大战僵尸,快速定位阳光基址 一丶基址,随机基址的理解 首先,全局变量的地址,我们都知道是固定的,是在PE文件中有保存的 但是高版本有了随机基址,那么要怎么解决这 ...
- 原生JS实现的h5小游戏-植物大战僵尸
代码地址如下:http://www.demodashi.com/demo/12755.html 项目介绍 本项目是利用原生js实现的h5小游戏-植物大战僵尸,主要结合了一下自己对于h5小游戏的理解,结 ...
- 植物大战僵尸:寻找阳光掉落Call调用
实验目标:通过遍历阳光产生的时间,寻找阳光产生的本地Call,使用代码注入器注入,自定义生成阳光 阳光CALL遍历技巧: 进入植物大战僵尸-> 当出现阳光后->马上搜索未知初始数值 返回游 ...
- java小项目之:植物大战僵尸,这个僵尸有点冷!内附素材源码
Java小项目之:植物大战僵尸! <植物大战僵尸>是由PopCap Games开发的一款益智策略类单机游戏,于2009年5月5日发售,这款游戏可谓是无人不知无人不晓. 在我身边,上到40岁 ...
- 【bzoj1565】 NOI2009—植物大战僵尸
http://www.lydsy.com/JudgeOnline/problem.php?id=1565 (题目链接) 题意 给出$n*m$的棋盘,僵尸攻击每个格子可以获得$v$的分数,每个格子又会保 ...
- 【最大权闭合子图 tarjan】bzoj1565: [NOI2009]植物大战僵尸
dinic+tarjan板子练手题 Description Plants vs. Zombies(PVZ)是最近十分风靡的一款小游戏.Plants(植物)和Zombies(僵尸)是游戏的主角,其 中P ...
- BZOJ1565: [NOI2009]植物大战僵尸
Description Input Output 仅包含一个整数,表示可以获得的最大能源收入.注意,你也可以选择不进行任何攻击,这样能源收入为0. Sample Input 3 2 10 0 20 0 ...
随机推荐
- linkinFrame--web应用举例--准备工作
OK,前面的博客我们已经搭好了linkinFrame的项目结构,现在我们这里添加一个简单的web应用,在编写此web应用的过程中我们来一步一步的搭好自己的框架. 现在开始,这里举一个例子,一个客户的C ...
- Global对象
1.Global对象是不需要创建实例就可以直接调用方法或属性的对象.有点类是于java中的工具类 2.关于汉字的网络传递 网络访问的过程中在传递数据的时候,传递的本质都是0101,如果你要传送字符的话 ...
- sparse_softmax_cross_entropy_with_logits
sparse_softmax_cross_entropy_with_logits 原创文章,请勿转载!!! 定义 sparse_softmax_cross_entropy_with_logits(_s ...
- 08_Python编码与解码
一.编码的由来 因为计算机只能处理010101二进制数据,如果要处理文本,图像,视频等,需要我们把数据转换成01010二进制格式才能被计算机处理 最先出现的是ASCII,用8位一个字节来表示,成为单字 ...
- 2018Pycharm激活方法
1.将"0.0.0.0 account.jetbrains.com"添加到hosts文件中 2.打开http://idea.lanyus.com/ 3.获取激活码,粘贴到第二个选项 ...
- 基于redis的cas实现
cas是我们常用的一种解决并发问题的手段,小到CPU指令集,大到分布式存储,都能看到cas的影子.本文假定你已经充分理解一般的cas方案,如果你还不知道cas是什么,请自行百度 我们在进行关系型数据库 ...
- grep工具及正则表达式
正则表达式和通配符 正则表达式与通配符不一样,它们表示的含义并不相同!正则表达式只是一种表示法,只要工具支持这种表示法,那么该工具就可以处理正则表达式的字符串.vim.grep.awk.sed都支持正 ...
- Sonar项目主要指标以及代码坏味道详解
更多原创测试技术文章同步更新到微信公众号 :三国测,敬请扫码关注个人的微信号,感谢! 原文链接:http://www.cnblogs.com/zishi/p/6766994.html 众所周知Sona ...
- Redis服务启动失败,提示:redis-server:command not found
今天我开始做主从复制的集群模式的测试,所以需要再装一个Linux操作系统,我在虚拟机里已经安装了一个Linux操作系统,Redis也已经配置好了.今天打算再安装一个Linux操作系统,Linux系统的 ...
- 机器学习00:如何通过Python入门机器学习
我们都知道机器学习是一门综合性极强的研究课题,对数学知识要求很高.因此,对于非学术研究专业的程序员,如果希望能入门机器学习,最好的方向还是从实践触发. 我了解到Python的生态对入门机器学习很有帮助 ...