题意:原题在这
原创翻译:
有一份只有一行的植物大战僵尸地图:
50hp的普通僵尸。
两种植物:豌豆射手(10hp)和土豆雷(一次性)。
每秒的操做步骤以下:
1.在最右侧的草皮中逐个放置0<=num的僵尸 (在最右边草皮的右边,即地图以外)
2.判断每个幸存的僵尸,是否站在一个豌豆射手身上:
if true,攻击这个豌豆射手,豌豆射手hp -1.豌豆射手的hp在那一刻多是负值,但它仍然活着!
if false,向左移动一格。
3.若是地图上还有僵尸,每个幸存的豌豆射手都会向最先放置的僵尸射击(僵尸每被锤一下hp -1,僵尸的hp在那一刻多是负值,但它仍然活着!)
4.若是在土豆雷的草皮中有僵尸,那么土豆雷爆炸,这个草皮中全部僵尸的hp变为0。
5.非正hp的植物和僵尸消失(直到如今它们已经死亡)
请根据所给的地图,求僵尸胜利的最小个数.
方法及思路:转自:全网惟一一篇题解
模拟,主要有三个问题要维护,一是植物的长度,二是最右边的植物种类,三是僵尸距离最近的植物的步数。
若是僵尸碰到了地雷,那么下一回合能够认为僵尸的最左位置为炸弹的左边。(僵尸左移)
若是碰到的不是地雷,则不停向左统计植物个数,直到遇到第一个炸弹
而后二分能够吃掉这些植物的最少僵尸个数,二分时要根据条件进行模拟。
其他详见代码注释↓
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 7 int T; 8 int P,M,len,Zombie,Step; 9 char plant[150]; 10 11 void init(char p[]) 12 { 13 Zombie=P=M=0; 14 len=strlen(p)-1; 15 for(int i=0;i<=len;i++) 16 { 17 if(p[i]=='P') 18 P++; 19 else 20 M++; 21 } 22 } 23 24 int solve(int sum,int plnt,int zom)//植物总数,豌豆个数,僵尸个数 25 { 26 int flag=Step;//距离最近植物的步数 27 int plnt_life=10,zom_life=50;//初始生命值 28 while(plnt>0 && zom>0) 29 { 30 if(flag>0)//还没到最近的植物 31 { 32 flag--;//走一步 33 zom_life-=sum;//这个僵尸会被全部植物锤 34 } 35 else//到了最近的植物 36 { 37 plnt_life-=zom;//这个豌豆会被全部僵尸锤 38 zom_life-=sum;//这个僵尸会被全部植物锤 39 } 40 if(plnt_life<=0)//死了一个射手 41 { 42 plnt_life=10; 43 sum--; plnt--; 44 flag=1; 45 } 46 if(zom_life<=0)//死了一个僵尸 47 { 48 zom_life=50; 49 zom--; 50 } 51 } 52 if(plnt<=0 && zom>0)//僵尸赢辣 53 return 1; 54 if(plnt<=0 && zom<=0)//都死光了 55 return 0; 56 if(plnt>0)//植物还活着 57 return -1; 58 } 59 60 int main() 61 { 62 cin>>T; 63 for(int cas=1;cas<=T;cas++) 64 { 65 cin>>plant; 66 init(plant); 67 if(plant[len]=='M')//有地雷 68 { 69 len--;//先牺牲一个僵尸玉石俱焚 70 Zombie++;//僵尸前进一步 71 Step=2; 72 } 73 else 74 Step=1; 75 while(len>=0)//只要还没到brain处 76 { 77 if(plant[len]=='M')//前面是地雷 78 { 79 if(Step>1)//还没到地雷 80 { 81 Step--;//走一步 82 if(P>=50) Zombie++;//而且打得过,那么干死一个僵尸 83 continue; 84 } 85 else 86 Zombie++;//死一个僵尸 87 M--; len--;//消耗一颗地雷 88 Step=2; 89 } 90 91 else//前面是豌豆射手 92 { 93 //从后往前统计豌豆个数 94 int pNum=0; 95 for(int i=len;i>=0;i--) 96 { 97 if(plant[i]=='M') 98 break; 99 else 100 pNum++; 101 } 102 //二分最少僵尸个数 103 int left=1,right=300,mid; 104 while(left<right)//直至二分出答案 105 { 106 mid=(left+right)>>1; 107 if(solve(P,pNum,mid)>0)//若是这种状况下僵尸赢 108 right=mid; 109 else 110 left=mid+1; 111 } 112 Zombie+=left;//加上二分出的答案 113 P-=pNum; 114 len-=pNum+1; 115 Step=2; 116 } 117 } 118 if(plant[0]=='M')//判断一开始是地雷 119 Zombie++; 120 printf("Case %d: %d\n",cas,Zombie); 121 } 122 return 0; 123 }