【最大权闭合图】BZOJ1565-[NOI2009]植物大战僵尸
害怕地发现我以前写的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]植物大战僵尸的更多相关文章
- BZOJ1565——[NOI2009]植物大战僵尸
1.题意:有一些点,点与点之间有保护关系,每个点都有一个权值,求能获得的最大值 2.分析:裸的最大权闭合图,用网络流进行求解,然后我们发现点与点之间的保护关系可能构成环,这样网络流是无法处理的,然后我 ...
- BZOJ1565: [NOI2009]植物大战僵尸
Description Input Output 仅包含一个整数,表示可以获得的最大能源收入.注意,你也可以选择不进行任何攻击,这样能源收入为0. Sample Input 3 2 10 0 20 0 ...
- 【最大权闭合子图 tarjan】bzoj1565: [NOI2009]植物大战僵尸
dinic+tarjan板子练手题 Description Plants vs. Zombies(PVZ)是最近十分风靡的一款小游戏.Plants(植物)和Zombies(僵尸)是游戏的主角,其 中P ...
- P2805 [NOI2009]植物大战僵尸
题目地址:P2805 [NOI2009]植物大战僵尸 最大权闭合子图 若有向图 \(G\) 的子图 \(V\) 满足: \(V\) 中顶点的所有出边均指向 \(V\) 内部的顶点,则称 \(V\) 是 ...
- 【bzoj1565】 NOI2009—植物大战僵尸
http://www.lydsy.com/JudgeOnline/problem.php?id=1565 (题目链接) 题意 给出$n*m$的棋盘,僵尸攻击每个格子可以获得$v$的分数,每个格子又会保 ...
- BZOJ 1565: [NOI2009]植物大战僵尸
1565: [NOI2009]植物大战僵尸 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 2317 Solved: 1071[Submit][Stat ...
- 图论(网络流):COGS 410. [NOI2009] 植物大战僵尸
410. [NOI2009] 植物大战僵尸 ★★★ 输入文件:pvz.in 输出文件:pvz.out 简单对比时间限制:2 s 内存限制:512 MB [问题描述] Plants vs ...
- COGS410. [NOI2009] 植物大战僵尸
410. [NOI2009] 植物大战僵尸 ★★★ 输入文件:pvz.in 输出文件:pvz.out 简单对比时间限制:2 s 内存限制:512 MB [问题描述] Plants vs ...
- 【BZOJ1565】 植物大战僵尸
Description Input Output 仅包含一个整数,表示可以获得的最大能源收入.注意,你也可以选择不进行任何攻击,这样能源收入为0. Sample Input 3 2 10 0 20 0 ...
随机推荐
- hdu 2962 Trucking (二分+最短路Spfa)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2962 Trucking Time Limit: 20000/10000 MS (Java/Others ...
- 7.0docker镜像和仓库
repository:镜像的仓库 registry :docker组件的仓库,docker镜像的存储服务 tag :镜像的标签 例:ubuntu:14.04 ubuntu:latest 删除镜像 d ...
- Coursera助学金申请模板
讲真,我觉得coursera的课还挺贵的.但是它有助学金系统,非常对我们穷学生友好了,而且基本上申请的都会批.不过现在助学金需要15个工作日才有答复,所以注意要提前申请. 有两大段要填. 虽然写的挺烂 ...
- vim查找/替换字符串【转】
转自:http://www.cnblogs.com/GODYCA/archive/2013/02/22/2922840.html vi/vim 中可以使用 :s 命令来替换字符串.该命令有很多种不同细 ...
- 给windows设置隐藏文件夹的方法
cls @ECHO OFF title Folder Private if EXIST "HTG Locker" goto UNLOCK if NOT EXIST Private ...
- glom模块的使用(一)
glom模块的使用 简单说下glom模块主要是处理结构化数据用的,安装简单pip install glom即可,下面就glom的方法参数做例子讲解. glom 和模块同名的glom方法使用方法: .g ...
- mongodb循环
var rds = db.REGIPATIENTREC.find({mzh:{$lt:"0"},usrOrg:"石景山中西医结合医院"}); var show ...
- vue 开始开发
1,引入vue.js文件 2,在body里用标签 编辑一个入口 <div id="app">{{msg}}</div> <-- 用双大括号 取数据显示 ...
- python_基于反射模拟Web框架路由系统
根据用户输入的内容,导入模块 #根据用户输入的内容,导入模块 inp = input("请输入模块名: ") print(inp,type(inp)) dd = __import_ ...
- POJ 1456 Supermarket(贪心+并查集)
题目链接:http://poj.org/problem?id=1456 题目大意:有n件商品,每件商品都有它的价值和截止售卖日期(超过这个日期就不能再卖了).卖一件商品消耗一个单位时间,售卖顺序是可以 ...