害怕地发现我以前写的Dinic几乎都是有错的……??!!!

【题目大意】

(以下摘自popoqqq大爷)给定一个m*n的草坪,每块草坪上的植物有两个属性:1.啃掉这个植物,获得收益x(可正可负)2.保护(r,c)点的植物不被啃掉。任何一个点的植物存活时,它左侧的所有植物都无法被攻击,求最大收益。

【思路】

首先我们很容易发现,植物存活有一个依赖关系,显然是一个最大权闭合图,即从被保护者指向保护者(简单来说,就是只有保护者被吃掉的情况下,被保护者才有可能被吃掉)。

注意,如果构成了一个环,则不会被吃掉;此外,当前点指向直接或间接指向一个环,也不可能被吃掉。

那么怎么删除环和指向环的节点呢?这里有一个拓扑排序常用的小技巧:

把所有边反向,从入度为0的点开始拓扑排序,能抵达的点便是保留的点。

顺便放一个拓扑排序的模板:

 1 void Topology()
2 {
3 memset(usable,0,sizeof(usable));
4 queue<int> que;
5 for (int i=S;i<=T;i++)
6 if (!into[i]) que.push(i);
7 while (!que.empty())
8 {
9 int head=que.front();que.pop();
10 usable[head]=1;
11 if (score[head]>0) ans+=score[head];
12 for (int i=0;i<rE[head].size();i++)
13 {
14 int to=rE[head][i];
15 into[to]--;
16 if (!into[to]) que.push(to);
17 }
18 }
19 }

【错误点】

一开始建图的时候正向边反向边傻傻没分清……

2016/7/29修改:突然我以前写的Dinic都是错的我要爆炸了!现在又优化了一下,更正详见注释里面。至于优化前后的效率差距:

呃……

 /*2016.7.29更正*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#define S 0
#define T m*n+1
using namespace std;
const int MAXN=;
struct node
{
int to,pos,cap;
};
const int INF=0x7fffffff;
vector<int> rE[MAXN*MAXN];
vector<node> E[MAXN*MAXN];
int score[MAXN*MAXN];
int n,m,ans=;
int usable[MAXN*MAXN],into[MAXN*MAXN];
int dis[MAXN*MAXN]; void addedge(int u,int v,int w)
{
rE[v].push_back(u);
into[u]++;
E[u].push_back((node){v,E[v].size(),w});
E[v].push_back((node){u,E[u].size()-,});
} void Topology()
{
memset(usable,,sizeof(usable));
queue<int> que;
for (int i=S;i<=T;i++)
if (!into[i]) que.push(i);
while (!que.empty())
{
int head=que.front();que.pop();
usable[head]=;
if (score[head]>) ans+=score[head];
for (int i=;i<rE[head].size();i++)
{
int to=rE[head][i];
into[to]--;
if (!into[to]) que.push(to);
}
}
} bool bfs()
{
memset(dis,-,sizeof(dis));
queue<int> que;
while (!que.empty()) que.pop();
que.push(S);
dis[S]=;
while (!que.empty())
{
int head=que.front();que.pop();
if (head==T) return true; //首次抵达T即可返回,不需要整张图全部分层
for (int i=;i<E[head].size();i++)
{
node tmp=E[head][i];
if (dis[tmp.to]==- && tmp.cap && usable[tmp.to])
{
dis[tmp.to]=dis[head]+;
que.push(tmp.to);
}
}
}
return false;
} int dfs(int s,int e,int f)
{
if (s==e) return f;
int ret=;
for (int i=;i<E[s].size();i++)
{
node &tmp=E[s][i];
if (dis[tmp.to]==dis[s]+ && tmp.cap)
{
int delta=dfs(tmp.to,e,min(f,tmp.cap));
if (delta>)
{
tmp.cap-=delta;
E[tmp.to][tmp.pos].cap+=delta;
f-=delta;
ret+=delta;
if (f==) return ret;
}
else dis[tmp.to]=-;//注意一下这里要清为-1,很重要★★★★★
}
}
return ret;
} void dinic()
{
while (bfs())
{
int f=dfs(S,T,INF);
if (f) ans-=f;else break;
}
} void init()
{
scanf("%d%d",&n,&m);
for (int i=;i<=n;i++)
for (int j=;j<=m;j++)
{
int w,fr=(i-)*m+j;
scanf("%d%d",&score[fr],&w);
if (score[fr]>) addedge(S,fr,score[fr]);
else if (score[fr]<) addedge(fr,T,-score[fr]);
for (int k=;k<=w;k++)
{
int r,c;
scanf("%d%d",&r,&c);
r++;c++;
int to=(r-)*m+c;
addedge(to,fr,INF);
}
if (j!=m) addedge(fr,fr+,INF);
}
} int main()
{
init();
Topology();
dinic();
printf("%d",ans);
return ;
}

【最大权闭合图】BZOJ1565-[NOI2009]植物大战僵尸的更多相关文章

  1. BZOJ1565——[NOI2009]植物大战僵尸

    1.题意:有一些点,点与点之间有保护关系,每个点都有一个权值,求能获得的最大值 2.分析:裸的最大权闭合图,用网络流进行求解,然后我们发现点与点之间的保护关系可能构成环,这样网络流是无法处理的,然后我 ...

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  9. 【BZOJ1565】 植物大战僵尸

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

随机推荐

  1. Select 使用不当引发的core,你应该知道的

    排查一个死机问题,搞了好几天时间,最终确定原因:最终确定问题原因,在此分享一下: 第一步:常规根据core文件查看栈信息,gdb –c core xxxx 如下rip不正确,指令地址错乱,栈信息已破坏 ...

  2. TCP之Nagle算法&&延迟ACK

    1. Nagle算法: 是为了减少广域网的小分组数目,从而减小网络拥塞的出现: 该算法要求一个tcp连接上最多只能有一个未被确认的未完成的小分组,在该分组ack到达之前不能发送其他的小分组,tcp需要 ...

  3. device tree --- #interrupt-cells property

    device tree source Example1 interrupt-controller@e000e100 { ... ... #interrupt-cells = <0x1>; ...

  4. tiny-rtems-src

    https://github.com/RTEMS/rtems-libbsd https://github.com/freebsd/freebsd/tree/642b174daddbd0efd9bb5f ...

  5. HIbernate学习笔记3 之 缓存和 对象的三种状态

    一.hibernate一级缓存 *  hibernate创建每个Session对象时,都会给该Session分配一块独立的缓冲区,用于存放Session查询出来的对象,这个分配给session的缓存区 ...

  6. java的关键字final

    final可以修饰类,成员方法,成员变量. 1.final修饰的类不能被继承,所以没有子类 final class First{ int num; } class Second extends Fir ...

  7. highcharts 折线,饼状,条状综合图

    完整代码如下: <head> <meta http-equiv="Content-Type" content="text/html; charset=u ...

  8. OpenCL与CUDA,CPU与GPU

    OpenCL OpenCL(全称Open Computing Language,开放运算语言)是第一个面向异构系统通用目的并行编程的开放式.免费标准,也是一个统一的编程环境,便于软件开发人员为高性能计 ...

  9. java入门概念梳理总结

    Java入门学习 简介 public class HelloWorld { public static void main(String []args) { System.out.println(&q ...

  10. hbase+hadoop+hdfs集群搭建 集成spring

    序言 最近公司一个汽车项目想用hbase做存储,然后就有了这篇文字,来,来,来, 带你一起征服hbase,并推荐一本书<hbase权威指南> 这是一本极好的hbase入门书籍,我花了一个晚 ...