zoukankan      html  css  js  c++  java
  • 【洛谷P2805】植物大战僵尸

    题目

    现在,我们将要考虑的问题是游戏中 Zombies 对 Plants 的进攻,请注意,本题中规则与实际游戏有所不同。游戏中有两种角色,Plants 和 Zombies,每个 Plant 有一个攻击位置集合,它可以对这些位置进行保护;而 Zombie 进攻植物的方式是走到植物所在的位置上并将其吃掉。

    游戏的地图可以抽象为一个 (N)(M) 列的矩阵,行从上到下用 (0)(N–1) 编号,列从左到右用 (0)(M–1) 编号;在地图的每个位置上都放有一个 Plant,为简单起见,我们把位于第 (r) 行第 (c) 列的植物记为 (P_{r, c})

    Plants 分很多种,有「攻击类」「防守类」和「经济类」等等。为了简单的描述每个 Plant,定义 (operatorname{Score})(operatorname{Attack}) 如下:

    • (operatorname{Score}(P_{r, c})) — Zombie 击溃植物 (P_{r, c}) 可获得的能源。
      (operatorname{Score}(P_{r, c})) 为非负整数,则表示击溃植物 (P_{r, c}) 可获得能源 (operatorname{Score}(P_{r, c})),若为负数表示击溃 (P_{r, c}) 需要付出能源 (-operatorname{Score}(P_{r, c}))

    • (operatorname{Attack}(P_{r, c})) — 植物 (P_{r, c}) 能够对 Zombie 进行攻击的位置集合。

    Zombies 必须从地图的右侧进入,且只能沿着水平方向进行移动。Zombies 攻击植物的唯一方式就是走到该植物所在的位置并将植物吃掉。因此 Zombies 的进攻总是从地图的右侧开始。也就是说,对于第 (r) 行的进攻,Zombies 必须首先攻击 (P_{r, M-1});若需要对 (P_{r, c})(0 le c < m - 1))攻击,必须将 (P_{r,M-1}, P_{r, M-2} cdots P_{r, c+1}) 先击溃,并移动到位置 ((r, c)) 才可进行攻击。

    在本题的设定中,Plants 的攻击力是无穷大的,一旦 Zombie 进入某个 Plant 的攻击位置,该 Zombie 会被瞬间消灭,而该 Zombie 没有时间进行任何攻击操作。因此,即便 Zombie 进入了一个 Plant 所在的位置,但该位置属于其他植物的攻击位置集合,则 Zombie 会被瞬间消灭而所在位置的植物则安然无恙(在我们的设定中,Plant 的攻击位置不包含自身所在位置,否则你就不可能击溃它了)。

    Zombies 的目标是对 Plants 的阵地发起进攻并获得最大的能源收入。每一次,你可以选择一个可进攻的植物进行攻击。本题的目标为,制定一套 Zombies 的进攻方案,选择进攻哪些植物以及进攻的顺序,从而获得最大的能源收入。

    思路

    最大权闭合子图模板题。
    发现如果要吃掉 ((i,j)) 的植物有两个限制:((i,j+1)) 被吃掉,且所有保护 ((i,j)) 的植物全部被吃掉。
    如果位置 ((i,j)) 的植物价值非负,那么我们从源点向它连一条边;否则将他向汇点连一条边,流量均为其价值的绝对值。
    然后考虑上述两种限制:显然如果 ((x_1,y_1)) 限制了 ((x_2,y_2)),我们可以从 ((x_2,y_2))((x_1,y_1)) 连一条流量为 (+infty) 的边。这样最大权闭合子图的模型就建立了。
    但是我们还需要考虑如果有若干植物互相保护形成了环,那么它们是一定都不可以选的,且这个环上任意植物保护的不在环上的植物都不可以选。
    所以我们可以先拓扑排序求出环,将环上的点标记好,不加入网络图中即可。
    注意拓扑排序需要将网络图上的边反向之后跑,因为网络图上的一条限制的边 (x o y) 指的是 (x)(y) 保护。

    代码

    #include <bits/stdc++.h>
    #define mp make_pair
    using namespace std;
    
    const int N=610,M=1000010,Inf=1e9;
    int n,m,maxf,tot=1,S,T,val[35][35],deg[N],head[N],cur[N],dep[N];
    vector<pair<int,int> > pro[35][35];
    
    struct edge
    {
    	int next,to,flow;
    }e[M];
    
    int ID(int x,int y)
    {
    	return (x-1)*m+y;
    }
    
    void add(int from,int to,int flow)
    {
    	e[++tot].to=to;
    	e[tot].flow=flow;
    	e[tot].next=head[from];
    	head[from]=tot;
    }
    
    void topsort()
    {
    	queue<int> q;
    	for (int i=1;i<N;i++)
    		if (!deg[i]) q.push(i);
    	while (q.size())
    	{
    		int u=q.front(); q.pop();
    		for (int i=head[u];~i;i=e[i].next)
    		{
    			int v=e[i].to;
    			deg[v]--;
    			if (!deg[v]) q.push(v);
    		}
    	}
    }
    
    bool bfs()
    {
    	memcpy(cur,head,sizeof(head));
    	memset(dep,0x3f3f3f3f,sizeof(dep));
    	queue<int> q;
    	q.push(S); dep[S]=0;
    	while (q.size())
    	{
    		int u=q.front(); q.pop();
    		for (int i=head[u];~i;i=e[i].next)
    		{
    			int v=e[i].to;
    			if (e[i].flow && !deg[v] && dep[v]>Inf)
    			{
    				dep[v]=dep[u]+1;
    				q.push(v);
    			}
    		}
    	}
    	return dep[T]<Inf;
    }
    
    int dfs(int x,int flow)
    {
    	if (x==T) return flow;
    	int res,used=0;
    	for (int i=cur[x];~i;i=e[i].next)
    	{
    		cur[x]=i;
    		int v=e[i].to;
    		if (e[i].flow && dep[v]==dep[x]+1)
    		{
    			res=dfs(v,min(e[i].flow,flow-used));
    			used+=res;
    			e[i].flow-=res; e[i^1].flow+=res;
    			if (used==flow) return flow;
    		}
    	}
    	return used;
    }
    
    void dinic()
    {
    	while (bfs())
    		maxf-=dfs(S,Inf);
    }
    
    int main()
    {
    	memset(head,-1,sizeof(head));
    	S=N-1; T=N-2;
    	scanf("%d%d",&n,&m);
    	for (int i=1;i<=n;i++)
    		for (int j=1,t,x,y;j<=m;j++)
    		{
    			scanf("%d%d",&val[i][j],&t);
    			if (val[i][j]>=0)
    			{
    				add(ID(i,j),S,1);
    				deg[S]++;
    			}
    			else
    			{
    				add(T,ID(i,j),1);
    				deg[ID(i,j)]++;
    			}
    			if (j<m)
    			{
    				add(ID(i,j+1),ID(i,j),1);
    				deg[ID(i,j)]++;
    			}
    			while (t--)
    			{
    				scanf("%d%d",&x,&y);
    				x++; y++;
    				pro[i][j].push_back(mp(x,y));
    				add(ID(i,j),ID(x,y),1);
    				deg[ID(x,y)]++;
    			}
    		}
    	topsort();
    	memset(head,-1,sizeof(head));
    	tot=1;
    	for (int i=1;i<=n;i++)
    		for (int j=1;j<=m;j++)
    			if (!deg[ID(i,j)])
    			{
    				if (val[i][j]>=0)
    				{
    					add(S,ID(i,j),val[i][j]);
    					add(ID(i,j),S,0);
    				}
    				else
    				{
    					add(ID(i,j),T,-val[i][j]);
    					add(T,ID(i,j),0);
    				}
    				if (j<m && !deg[ID(i,j+1)])
    				{
    					add(ID(i,j),ID(i,j+1),Inf);
    					add(ID(i,j+1),ID(i,j),0);
    				}
    				for (int k=0;k<pro[i][j].size();k++)
    				{
    					int x=pro[i][j][k].first,y=pro[i][j][k].second;
    					add(ID(x,y),ID(i,j),Inf);
    					add(ID(i,j),ID(x,y),0);
    				}
    			}
    	dinic();
    	for (int i=1;i<=n;i++)
    		for (int j=1;j<=m;j++)
    			if (!deg[ID(i,j)] && val[i][j]>0) maxf+=val[i][j];
    	printf("%d",maxf);
    	return 0;
    }
    
  • 相关阅读:
    LeetCode "Jump Game"
    LeetCode "Pow(x,n)"
    LeetCode "Reverse Linked List II"
    LeetCode "Unique Binary Search Trees II"
    LeetCode "Combination Sum II"
    LeetCode "Divide Two Integers"
    LeetCode "First Missing Positive"
    LeetCode "Clone Graph"
    LeetCode "Decode Ways"
    LeetCode "Combinations"
  • 原文地址:https://www.cnblogs.com/stoorz/p/14039032.html
Copyright © 2011-2022 走看看