【NOI2009】 植物大战僵尸

题目描述
植物大战僵尸

【问题描述】
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的进攻方案,选择进攻哪些植物以及进攻的顺序,从而获得最大的能源收入。

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

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

【输入样例】
3 2
10 0
20 0
-10 0
-5 1 0 0
100 1 2 1
100 0

【输出样例】
25

【样例说明】
在样例中, 植物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 ≤ 201 ≤ M ≤ 30,-10000 ≤ Score ≤ 10000

 

题解

 

解法1:搜索
 1 program pvz;
 2 type
 3   ty3=array[0..30,0..20] of longint;
 4   ty1=^ty2;
 5   ty2=record
 6     x,y:longint;
 7     next:ty1;
 8   end;
 9 var
10   n,m,i,j,k,l,x,y,ans:longint;
11   first:array[0..30,0..20] of ty1;
12   map,scr:ty3;
13   get:array[0..30,0..20] of boolean;
14 //===================
15 procedure insert(x,y,i,j:longint);
16 var
17   p:ty1;
18 begin
19   new(p);
20   p^.x:=i;
21   p^.y:=j;
22   p^.next:=first[x,y];
23   first[x,y]:=p;
24 end;
25 //===================
26 procedure find(s:longint);
27 var
28   i,j:longint;
29   p:ty1;
30 begin
31   if ans<s then ans:=s;
32   for i:=1 to n do
33   for j:=1 to m do
34   if (map[i,j]=0)and(not get[i,j])and(get[i-1,j]) then
35   begin
36     get[i,j]:=true;
37     p:=first[i,j];
38     while p<>nil do
39     begin
40       dec(map[p^.x,p^.y]);
41       p:=p^.next;
42     end;
43     find(s+scr[i,j]);
44     get[i,j]:=false;
45     p:=first[i,j];
46     while p<>nil do
47     begin
48       inc(map[p^.x,p^.y]);
49       p:=p^.next;
50     end;
51   end;
52 end;
53 //===================
54 begin
55   assign(input,'pvz.in'); reset(input);
56   assign(output,'pvz.out'); rewrite(output);
57   read(n,m);
58   for i:=1 to n do
59   for j:=1 to m do
60   begin
61     read(scr[m-j+1,i],k);
62     for l:=1 to k do
63     begin
64       read(x,y);
65       insert(m-j+1,i,m-y,x+1);
66       inc(map[m-y,x+1]);
67     end;
68   end;
69   k:=m; m:=n; n:=k;
70   for i:=1 to m do get[0,i]:=true;
71   find(0);
72   writeln(ans);
73   close(input); close(output);
74 end.

 

解法2:网络流
 1 program pvz;
 2 const max=10000000;
 3 var
 4   n,m,tot,s,t:longint;
 5   g:array[0..1000,0..1000] of longint;
 6   d,vd,rb,scr:array[0..1000] of longint;
 7 //==================
 8 function min(a,b:longint):longint;
 9 begin
10   if a<b then exit(a) else exit(b);
11 end;
12 //==================
13 procedure built;
14 var
15   i,j,l,k,x,y,p:longint;
16 begin
17   read(n,m);
18   s:=0; t:=n*m+1;
19   for i:=1 to n do
20   for j:=1 to m do
21   begin
22     read(scr[(i-1)*m+j],k);
23     p:=scr[(i-1)*m+j];
24     if p>=0 then
25     begin
26       g[s,(i-1)*m+j]:=p;
27       inc(tot,p);
28     end else g[(i-1)*m+j,t]:=-p;
29     for l:=1 to k do
30     begin
31       read(x,y);
32       if g[x*m+y+1,(i-1)*m+j]=0 then inc(rb[x*m+y+1]);
33       g[x*m+y+1,(i-1)*m+j]:=max;
34     end;
35     if j>1 then
36     begin
37       if g[(i-1)*m+j-1,(i-1)*m+j]=0 then inc(rb[(i-1)*m+j-1]);
38       g[(i-1)*m+j-1,(i-1)*m+j]:=max;
39     end;
40   end;
41   while true do
42   begin
43     p:=0;
44     for j:=1 to t-1 do
45     if rb[j]=0 then
46     begin p:=j; break; end;
47     if p=0 then break;
48     rb[p]:=max;
49     for k:=1 to t-1 do
50     if g[k,p]>0 then dec(rb[k]);
51   end;
52   for i:=1 to t-1 do
53   if rb[i]<10000 then
54   begin
55     g[s,i]:=0; g[i,t]:=0;
56     if scr[i]>0 then dec(tot,scr[i]);
57   end;
58 end;
59 //==================
60 function sap(x,flow:longint):longint;
61 var
62   i,tmp:longint;
63 begin
64   if x=t then exit(flow);
65   sap:=0;
66   for i:=0 to t do
67   if (g[x,i]>0)and(d[i]+1=d[x]) then
68   begin
69     tmp:=sap(i,min(flow-sap,g[x,i]));
70     dec(g[x,i],tmp);
71     inc(g[i,x],tmp);
72     inc(sap,tmp);
73     if sap=flow then exit;
74   end;
75   if d[s]=t+1 then exit;
76   dec(vd[d[x]]);
77   if vd[d[x]]=0 then d[s]:=t+1;
78   inc(d[x]); inc(vd[d[x]]);
79 end;
80 //==================
81 procedure main;
82 var
83   flow:longint;
84 begin
85   flow:=0;
86   vd[0]:=t+1;
87   while d[s]<t+1 do inc(flow,sap(s,maxlongint));
88   writeln(tot-flow);
89 end;
90 //==================
91 begin
92   assign(input,'pvz.in'); reset(input);
93   assign(output,'pvz.out'); rewrite(output);
94   built;
95   main;
96   close(input); close(output);
97 end.
posted @ 2012-05-16 11:26  datam  阅读(277)  评论(0编辑  收藏  举报