害怕地发现我以前写的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. VMware 12安装虚拟机Mac OS X 10.10不能上网问题

    1:从本机中选择打开连接网络,选择本地连接.如果是无线网可以选择无线网. 1:  2: 控制面板--->网络和共享中心 2:选择属性,点击共享按钮. 3:将internet连接共享下面选项都选中 ...

  2. ipython notebook环境搭建

    默认已经装好python基本环境,再进行下面步骤: 1. 下载安装IPython:  c:>pip.exe install ipython 系统就会去网上寻找ipython的包, 进行下载及安装 ...

  3. 【转】MP3文件原理及结构解析

    1.引言文件压缩技术的日新月异使得MP3成为时下最烫手的音乐格式,优质的音乐随着0与1的排列迅速散布 到世界各地,撼动人心.何谓MP3?MP3的全称是MPEG Audio Layer 3,它是一种高效 ...

  4. BP神经网络-- 基本模型

    转载:http://www.cnblogs.com/jzhlin/archive/2012/07/28/bp.html BP 神经网络中的 BP 为 Back  Propagation 的简写,最早它 ...

  5. 原始套接字&&数据链路层访问

    1. 原始套接字能力: (1) 进程可以读写ICMP,IGMP等分组,如ping程序: (2) 进程可以读写内核不处理协议字段的ipv4数据报:如OSPF等: (3) 进程可以使用IP_HDRINCL ...

  6. python基础===进程,线程,协程的区别(转)

    本文转自:http://blog.csdn.net/hairetz/article/details/16119911 进程拥有自己独立的堆和栈,既不共享堆,亦不共享栈,进程由操作系统调度. 线程拥有自 ...

  7. 创建.dat文件(转载)

    比较有用的东比较有用的东西 首先,批处理文件是一个文本文件,这个文件的每一行都是一条DOS命令(大部分时候就好象我们在DOS提示符下执行的命令行一样),你可以使用DOS下的Edit或者Windows的 ...

  8. 使用cmd(黑窗口)敲命令使用远程数据库

    C:\Users\gzz>mysql -h 10.27.104.176 -u root -p mysql

  9. python 基础习题

    1.8<<2等于? 8 ---> 1000 32 ---> 100000 -----------结果--- 32 2.通过内置函数计算5除以2的余数 print(dir()) ...

  10. opencv 图像转换

    #include <cv.h> #include <highgui.h> int main() { CvPoint2D32f srcTri[], dstTri[]; CvMat ...