bzoj1565【NOI2009】植物大战僵尸

1565: [NOI2009]植物大战僵尸

Time Limit: 10 Sec  Memory Limit: 64 MB

Submit: 2034  Solved: 944

[Submit][Status][Discuss]

Description

Input

Output

仅包含一个整数,表示可以获得的最大能源收入。注意,你也可以选择不进行任何攻击,这样能源收入为0。

Sample Input

3 2

10 0

20 0

-10 0

-5 1 0 0

100 1 2 1

100 0

Sample Output

25

HINT

在样例中, 植物P1,1可以攻击位置(0,0), P2, 0可以攻击位置(2,1)。

一个方案为,首先进攻P1,1, P0,1,此时可以攻击P0,0 。共得到能源收益为(-5)+20+10 = 25。注意, 位置(2,1)被植物P2,0保护,所以无法攻击第2行中的任何植物。

【大致数据规模】

约20%的数据满足1 ≤ N, M ≤ 5;

约40%的数据满足1 ≤ N, M ≤ 10;

约100%的数据满足1 ≤ N ≤ 20,1 ≤ M ≤ 30,-10000 ≤ Score ≤ 10000 。

网络流+最大权闭合子图+拓扑排序

这道题有一个隐藏条件:每个植物除了保护给出的位置外,还保护它左面的节点。

然后把所有植物的保护关系建出图,有一些植物之间是环状结构的,这显然不能被吃,所以我们用拓扑排序去掉图中的环。

题目转化为:有一些点,点有点权,吃掉某一个点必须先吃掉某些点,求最多能吃掉的权值。

这符合最大权闭合子图的定义,用最小割求最大权闭合子图即可。

最大权闭合子图求法详见bzoj1497。

#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#define F(i,j,n) for(int i=j;i<=n;i++)
#define D(i,j,n) for(int i=j;i>=n;i--)
#define p(x,y) ((x-1)*m+y)
#define ll long long
#define N 1000
#define M 800005
#define inf 1000000000
using namespace std;
int n,m,s,t,cnt=1,ans;
int w[N],ind[N],head[N],cur[N],dis[N];
vector<int> v[N];
queue<int> q;
struct edge{int next,to,v;}e[M];
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
	while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
inline void add_edge(int x,int y,int v)
{
	e[++cnt]=(edge){head[x],y,v};head[x]=cnt;
	e[++cnt]=(edge){head[y],x,0};head[y]=cnt;
}
bool bfs()
{
	while (!q.empty()) q.pop();
	memset(dis,-1,sizeof(dis));
	dis[s]=0;q.push(s);
	while (!q.empty())
	{
		int x=q.front();q.pop();
		if (x==t) return true;
		for(int i=head[x];i;i=e[i].next)
		{
			int y=e[i].to;
			if (e[i].v&&dis[y]==-1) dis[y]=dis[x]+1,q.push(y);
		}
	}
	return false;
}
int dfs(int x,int f)
{
	if (x==t) return f;
	int sum=0,tmp;
	for(int &i=cur[x];i;i=e[i].next)
	{
		int y=e[i].to;
		if (e[i].v&&dis[y]==dis[x]+1)
		{
			tmp=dfs(y,min(e[i].v,f-sum));
			e[i].v-=tmp;e[i^1].v+=tmp;sum+=tmp;
			if (sum==f) return sum;
		}
	}
	if (!sum) dis[x]=-1;
	return sum;
}
int dinic()
{
	int ret=0;
	while (bfs())
	{
		F(i,1,t) cur[i]=head[i];
		ret+=dfs(s,inf);
	}
	return ret;
}
int main()
{
	n=read();m=read();s=n*m+1;t=s+1;
	F(i,1,n) F(j,1,m)
	{
		w[p(i,j)]=read();int num=read();
		F(k,1,num)
		{
			int x=read()+1,y=read()+1;
			v[p(i,j)].push_back(p(x,y));
			ind[p(x,y)]++;
		}
	}
	F(i,1,n) F(j,1,m-1)
	{
		v[p(i,j+1)].push_back(p(i,j));
		ind[p(i,j)]++;
	}
	F(i,1,n*m) if (!ind[i]) q.push(i);
	while (!q.empty())
	{
		int x=q.front();q.pop();
		for(int i=0;i<v[x].size();i++)
		{
			int y=v[x][i];ind[y]--;
			if (!ind[y]) q.push(y);
		}
	}
	F(i,1,n*m) if (!ind[i])
	{
		if (w[i]>=0) add_edge(s,i,w[i]),ans+=w[i];
		else add_edge(i,t,-w[i]);
		for(int j=0;j<v[i].size();j++)
		{
			int x=v[i][j];
			if (!ind[x]) add_edge(x,i,inf);
		}
	}
	ans-=dinic();
	printf("%d\n",ans);
}
时间: 2024-08-29 20:56:20

bzoj1565【NOI2009】植物大战僵尸的相关文章

Bzoj1565 [NOI2009]植物大战僵尸

Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 2363  Solved: 1092 Description Input Output 仅包含一个整数,表示可以获得的最大能源收入.注意,你也可以选择不进行任何攻击,这样能源收入为0. Sample Input 3 2 10 0 20 0 -10 0 -5 1 0 0 100 1 2 1 100 0 Sample Output 25 HINT 在样例中, 植物P1,1可以攻击位置(0,0), P2, 0

NOI2009植物大战僵尸

这题应该分两步来做: 1.拓扑排序,去掉无敌点 2.求最大闭合子图 需要注意几点: 1.拓扑排序时,如果(i,j)可以攻击到(x,y),那么增加(x,y)的入度,而不是(i,j)的入度 因为入度代表着要攻击它需要事先攻击几个点 2.求最大闭合子图时,用所有的正权点-最大流 3.求最大闭合子图时,如果(i,j)可以攻击到(x,y),那么连一条边(x,y)到(i,j),容量为正无穷 因为在最大闭合子图中边(x,y)到(i,j)意味着选(x,y)就必须要选(i,j),这与实际含义相符 4.s到正权点,

COGS410. [NOI2009] 植物大战僵尸

410. [NOI2009] 植物大战僵尸 ★★★   输入文件:pvz.in   输出文件:pvz.out   简单对比时间限制:2 s   内存限制:512 MB [问题描述] Plants vs. Zombies(PVZ)是最近十分风靡的一款小游戏.Plants(植物)和Zombies(僵尸)是游戏的主角,其中Plants防守,而Zombies进攻.该款游戏包含多种不同的挑战系列,比如Protect Your Brain.Bowling等等.其中最为经典的,莫过于玩家通过控制Plants来

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

410. [NOI2009] 植物大战僵尸 ★★★   输入文件:pvz.in   输出文件:pvz.out   简单对比时间限制:2 s   内存限制:512 MB [问题描述] Plants vs. Zombies(PVZ)是最近十分风靡的一款小游戏.Plants(植物)和Zombies(僵尸)是游戏的主角,其中Plants防守,而Zombies进攻.该款游戏包含多种不同的挑战系列,比如Protect Your Brain.Bowling等等.其中最为经典的,莫过于玩家通过控制Plants来

bzoj 1565 [NOI2009]植物大战僵尸

拓扑排序+最小割. 每个植物有它保护的一些植物,等价于选一些点的先决条件是其它一些点,最大权闭合子图问题. 发现图里有环,所以环里的点都不能选,先决条件是环里的点的点也不能选,所以把所有边反向拓扑排序,拓扑不到的点不能选. 无视掉不能选的点后裸最大权闭合子图建图就好了. 一个最大权闭合子图裸题的题解 1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<algorithm>

【BZOJ1565】 植物大战僵尸

Description Input Output 仅包含一个整数,表示可以获得的最大能源收入.注意,你也可以选择不进行任何攻击,这样能源收入为0. Sample Input 3 2 10 0 20 0 -10 0 -5 1 0 0 100 1 2 1 100 0 Sample Output 25 Solution 按照依赖关系建立有向图:若清除$a$前必须清除$b$,则连边$a$至$b$.这些依赖关系包括同行植物左边对右边的依赖,以及被保护者对保护者的依赖. 首先不能考虑开挂集团,也就是依赖关系

luogu2805 [NOI2009]植物大战僵尸

想象一下,要搞掉一个植物,必须先搞掉另一些植物--我们可以发现这是一个最大权闭合子图的问题. 最大权闭合子图的话,太空飞行计划问题是一个入门题,可以一看. 然而我们手玩一下样例就会惊恐地发现,保护关系出现了环. 比如说: 从 i 到 j 的箭头是说要搞 i 就要先搞 j,这是为了和最大权闭合子图的模型对应. 要搞 3 就要先搞 4,要搞 4 就要先搞 5,要搞 5 就要先搞 3--简直是乱来-- 这就像是一个无冷却食人花前面放一个坚果 所以就要删环了,把边倒过来拓扑排序一下,能被拓扑到的点就是合

NOI2009 植物大战僵尸

啊一道好题感觉写得挺爽的啊这题这种有一点懵逼然后学了一点东西之后很明朗的感觉真是好!预处理参考 :http://www.cppblog.com/MatoNo1/archive/2014/11/01/142798.html?opt=admin建图参考 :http://hihocoder.com/problemset/problem/1398?sid=1010444 #include<iostream> #include<cstdio> #include<cstdlib>

[Luogu 2805]NOI2009 植物大战僵尸

<题目链接> 这题是个比较经典的最大权闭合子图,可以建图转化为最小割问题,再根据最大流最小割定理,采用任意一种最大流算法求得. 对于每个点,如果点权w为正,则从源点到这个点连一条边权为w的有向边:否则如果w为负则从这个点到汇点连一条有向边.加边的时候预处理出反图的每个点入度. 其次,每一个被保护的点到保护它的点连一条边权为INF的有向边. 注意同一行的左侧点受到右侧点的间接保护,因此对于每一个不位于当前行最右的点,都要向其右侧的一个点连一条INF有向边(连一条即可,不必连所有). 初始化完成后

98植物大战僵尸OL_僵尸迷阵

最近在玩植物大战僵尸Ol打到僵尸迷阵,打了个700分倒数第一,擦.....俗话说的好,失败是成功的妈妈,于是花了点时间写了一个小玩意,我相信下次我一定能拿第一 代码非常简单: using UnityEngine; using System.Collections; using UnityEngine.UI; public class MyScript : MonoBehaviour { // Use this for initialization void Start () { } // Upd