BZOJ 1565: [NOI2009]植物大战僵尸 网络流:最大权闭合子图

版权声明:转载注明即可。。 https://blog.csdn.net/huashuimu2003/article/details/91490277

title

BZOJ 1565
LUOGU 2805
Description

Plants vs. Zombies(PVZ)是最近十分风靡的一款小游戏。Plants(植物)和Zombies(僵尸)是游戏的主角,其中Plants防守,而Zombies进攻。该款游戏包含多种不同的挑战系列,比如Protect Your Brain、Bowling等等。其中最为经典的,莫过于玩家通过控制Plants来防守Zombies的进攻,或者相反地由玩家通过控制Zombies对Plants发起进攻。
现在,我们将要考虑的问题是游戏中Zombies对Plants的进攻,请注意,本题中规则与实际游戏有所不同。游戏中有两种角色,Plants和Zombies,每个Plant有一个攻击位置集合,它可以对这些位置进行保护;而Zombie进攻植物的方式是走到植物所在的位置上并将其吃掉。
游戏的地图可以抽象为一个N行M列的矩阵,行从上到下用0到N–1编号,列从左到右用0到M–1编号;在地图的每个位置上都放有一个Plant,为简单起见,我们把位于第r行第c列的植物记为Pr, c。
Plants分很多种,有攻击类、防守类和经济类等等。为了简单的描述每个Plant,定义Score和Attack如下:
Score[Pr, c]
Zombie击溃植物Pr, c可获得的能源。若Score[Pr, c]为非负整数,则表示击溃植物Pr, c可获得能源Score[Pr, c],若为负数表示击溃Pr, c需要付出能源 -Score[Pr, c]。
Attack[Pr, c]
植物Pr, c能够对Zombie进行攻击的位置集合。Zombies必须从地图的右侧进入,且只能沿着水平方向进行移动。Zombies攻击植物的唯一方式就是走到该植物所在的位置并将植物吃掉。因此Zombies的进攻总是从地图的右侧开始。也就是说,对于第r行的进攻,Zombies必须首先攻击Pr, M-1;若需要对Pr, c(0 ≤ c < M-1)攻击,必须将Pr,M-1, Pr, M-2 … Pr, c+1先击溃,并移动到位置(r, c)才可进行攻击。
在本题的设定中,Plants的攻击力是无穷大的,一旦Zombie进入某个Plant的攻击位置,该Zombie会被瞬间消灭,而该Zombie没有时间进行任何攻击操作。因此,即便Zombie进入了一个Plant所在的位置,但该位置属于其他植物的攻击位置集合,则Zombie会被瞬间消灭而所在位置的植物则安然无恙(在我们的设定中,Plant的攻击位置不包含自身所在位置,否则你就不可能击溃它了)。
Zombies的目标是对Plants的阵地发起进攻并获得最大的能源收入。每一次,你可以选择一个可进攻的植物进行攻击。本题的目标为,制定一套Zombies的进攻方案,选择进攻哪些植物以及进攻的顺序,从而获得最大的能源收入。

Input

第一行包含两个整数N, M,分别表示地图的行数和列数。
接下来N×M行描述每个位置上植物的信息。第r×M + c + 1行按照如下格式给出植物Pr, c的信息:
第一个整数为Score[Pr, c], 第二个整数为集合Attack[Pr, c]中的位置个数w,
接下来w个位置信息(r’, c’),表示Pr, c可以攻击位置第r’ 行第c’ 列。
1 ≤ N ≤ 20,1 ≤ M ≤ 30,-10000 ≤ Score ≤ 10000 。

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

analysis

懒病犯了,到神犇那里吧。。 \to BYVoid

code

#include<bits/stdc++.h>
using namespace std;
const int maxn=1010,maxm=1e6+10,inf=0x3f3f3f3f;

char buf[1<<15],*fs,*ft;
inline char getc() { return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++; }
template<typename T>inline void read(T &x)
{
	x=0;
	T f=1, ch=getchar();
	while (!isdigit(ch) && ch^'-') ch=getchar();
	if (ch=='-') f=-1, ch=getchar();
	while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
	x*=f;
}

template<typename T>inline void write(T x)
{
	if (!x) { putchar('0'); return ; }
	if (x<0) putchar('-'), x=-x;
	T num=0, ch[20];
	while (x) ch[++num]=x%10+48,x/=10;
	while (num) putchar(ch[num--]);
}

int ver[maxm],edge[maxm],Next[maxm],head[maxn],len=1;
inline void add(int x,int y,int z)
{
	ver[++len]=y,edge[len]=z,Next[len]=head[x],head[x]=len;
	ver[++len]=x,edge[len]=0,Next[len]=head[y],head[y]=len;
}

int s,t;
int dist[maxn];
inline bool bfs()
{
	queue<int>q;
	memset(dist,0,sizeof(dist));
	q.push(s),dist[s]=1;
	while (!q.empty())
	{
		int x=q.front();
		q.pop();
		for (int i=head[x]; i; i=Next[i])
		{
			int y=ver[i];
			if (edge[i] && !dist[y])
			{
				dist[y]=dist[x]+1;
				if (y==t) return 1;
				q.push(y);
			}
		}
	}
	return 0;
}

inline int get(int x,int low)
{
	if (x==t) return low;
	int tmp=low;
	for (int i=head[x]; i; i=Next[i])
	{
		int y=ver[i];
		if (edge[i] && dist[y]==dist[x]+1)
		{
			int a=get(y,min(tmp,edge[i]));
			if (!a) dist[y]=0;
			edge[i]-=a;
			edge[i^1]+=a;
			if (!(tmp-=a)) break;
		}
	}
	return low-tmp;
}

int n,m,In[maxn];
inline int hash(int i,int j)
{
	return (i-1)*m+j;
}

vector<int>Out[maxn];
bool vis[maxn];
inline void topsort()
{
	queue<int>Q;
	for (int i=1; i<=n; ++i)
		for (int j=1; j<=m; ++j)
			if (!In[hash(i,j)]) Q.push(hash(i,j)),vis[hash(i,j)]=1;
	while (!Q.empty())
	{
		int x=Q.front();
		Q.pop();
		for (int i=0; i<Out[x].size(); ++i)
		{
			int y=Out[x][i];
			--In[y];
			if (!vis[y] && !In[y]) Q.push(y),vis[y]=1;
		}
	}
}

int sc[maxn],r[maxn],c[maxn];
int main()
{
	
	read(n);read(m);
	for (int i=1; i<=n; ++i)
		for (int j=1,w; j<=m; ++j)
		{
			read(sc[hash(i,j)]),read(w);
			for (int k=1,x,y; k<=w; ++k)
			{
				read(x);read(y);
				++x,++y;
				Out[hash(i,j)].push_back(hash(x,y));
				++In[hash(x,y)];
			}
			if (j<m)
			{
				Out[hash(i,j+1)].push_back(hash(i,j));
				++In[hash(i,j)];
			}
		}
	topsort();
	s=0,t=maxn-1;
	int sum=0;
	for (int i=1; i<=n; ++i)
		for (int j=1; j<=m; ++j)
		{
			int x=hash(i,j);
			if (!vis[x]) continue;

			if (sc[x]>=0) add(s,x,sc[x]),sum+=sc[x];
			else add(x,t,-sc[x]);

			for (int k=0; k<Out[x].size(); ++k)
			{
				int y=Out[x][k];
				if (!vis[y]) continue;
				add(y,x,inf);
			}
		}

	int ans=0;
	while (bfs()) ans+=get(s,inf);
	write(sum-ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/huashuimu2003/article/details/91490277
今日推荐