害怕地发现我以前写的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. skb管理函数之alloc_skb、dev_alloc_skb、kfree_skb、dev_kfree_skb、consume_skb

    alloc_skb--分配skb dev_alloc_skb--分配skb,通常被设备驱动用在中断上下文中,它是alloc_skb的封装函数,因为在中断处理函数中被调用,因此要求原子操作(GFP_AT ...

  2. mac系统中实现vitualBox中访问内网端口

    第一步,增加外网网段 打开vitualbox后,按管理菜单,点击->主机网络管理器,如图1所示.点击创建,创建下个网络主机. 图1 然后,关掉虚拟机,虚拟机的设置中,找到网络选项卡,然后点击网络 ...

  3. C后端设计开发 - 第6章-武技-常见组件上三路

    正文 第6章-武技-常见组件上三路 后记 如果有错误, 欢迎指正. 有好的补充, 和疑问欢迎交流, 一块提高. 在此谢谢大家了.

  4. centos 6 编译安装php-5.4/5.5(lamp模式)

    在安装LAMP架构时,我们常用php-5.3的版本 现进行php-5.4/5.5的编译安装演示: [root@localhost ~]# cd /usr/local/src [root@localho ...

  5. 在 Visual Studio 中使用正则表达式

    Visual Studio 使用 .NET framework 正则表达式查找和替换文本. 在 Visual Studio 2010 和早期版本中,Visual Studio 在“查找和替换”窗口中使 ...

  6. JQuery一个对象绑定多个事件

    jQuery("#id").click(func1).mouseover(func2)//方法连写,func为方法的名字 jQuery("#id").click ...

  7. 关于自适应屏幕,设置子元素浮动,父div不能包裹子div,子元素中内容溢出的问题。

    设置HTML适应不同分辨率的屏幕. 需求结构如下: HTML结构代码如下(只是其中一条): <body> <div class="content">< ...

  8. LightOJ - 1234

    Harmonic Number Time Limit: 3000MS   Memory Limit: 32768KB   64bit IO Format: %lld & %llu Descri ...

  9. jpa缓存导致无法查询到更新后的数据&android出现ANR的一个解决办法

    1. 向服务器更新记录后查询,始终查询不到更新后的信息 只能查到更新之前的,马上推断出是缓存的问题.网上搜索一番,将问题定位为jpa缓存,我们要设置jpa查询时不从缓存中取,直接从数据库中取,这样便能 ...

  10. Gray Code——陈瑶师姐面试时候要用回溯算法

    The gray code is a binary numeral system where two successive values differ in only one bit. Given a ...