[知识点] 2.1 枚举与模拟
总目录 > 2 算法基础 > 2.1 枚举与模拟
前言
这篇文章是在不知道该写些什么,但是作为算法里最基本的东西,还是得给点排面哈。
子目录列表
1、枚举算法
2、模拟算法
2.1 枚举与模拟
1、枚举算法
枚举是基于现有知识来猜测答案的一种问题求解策略,是最最基础的算法之一,基本上没有难度。随便举个例子。
【例子】求 1 到 n 的和。
for (int i = 1; i <= n; i++) sum += i;
2、模拟算法
模拟是指通过计算机来模拟题目要求的操作。同样是很简单的一类题型,但其上限并不低。它可以很简单,比如:
【例子】小户和小口玩 n 轮石头剪刀布,每次给出他们每一轮出的拳,求他们最后谁胜利次数更多。1 表示石头,2 表示剪刀,3 表示布。
1 cin >> n; 2 for (int i = 1; i <= n; i++) { 3 cin >> a >> b; 4 if (a == 1) { 5 if (b == 2) h++; 6 if (b == 3) k++; 7 } 8 else if (a == 2) { 9 if (b == 1) k++; 10 if (b == 3) h++; 11 } 12 else { 13 if (b == 1) h++; 14 if (b == 2) k++; 15 } 16 cout << (h > k ? "huhu" : h < k ? "koko" : "draw"); 17 }
但如果出题人丧心病狂提高难度,或者出现在一些比赛中,往往会成为很恶心的题,因为它给出的模拟框架可以很大很大,比如:
【2019 ICPC Asia Nanchang Regional】【Resistance】
Recently, Sheep gets fascinated in a tower defense game called ResistanceResistance. But now he is stuck at the 99-th level. He doesn't know what to do and hopes for your help.
ResistanceResistanceis a tower defense game. The map used in this game is an n×n. A specific path consisting of several cells is given in which any two adjacent cells share a common edge. We guarantee that the path never passes by a cell twice. A village is locating at the destination of the path. Some evil invaders will land at the starting point, go along the path and attempt to invade the village.
To secure the village, Sheep has deployed k defense towers in the map to attack invaders. All defense towers are lying at some locations but neither on the path nor at the starting point or the destination. All defense towers can be divided into two kinds: gun towers and bunkers.
A gun tower is armed with the machine gun, whose effective range is up to r1. Under normal circumstances, it selects the nearest target within the range and fire, causing d1 damage points for its target. If there are more than one nearest enemies (with the same smallest Euclidean distance), the one who can reach the village with least steps on the path. The rules of the game guarantee that there wouldn't be more ambiguities. After an attack, the machine gun will need t1 frames of time for reloading ammunition, so it would not be used again until the (x+t1)-th frame if it fired at the xx-th frame.
A bunker is armed with a flame thrower, whose effective range is up to r2. It can fire at every time without any restrictions like gun towers. It also selects a target satisfying the similar conditions as above. An attack will cause d2 damage points for its target, and the attacked invader will start to burn in the next frame of time. At each frame when the invader is burning, it suffers from d3 damage points.The fire will be quenched at the end of the (x+t2)-th frame if was hit by a bunker at the x-th frame. Moreover, if a burning invader was hit by a bunker again, supposing that it was hit at the y-th frame, its burning time will be prolonged to the end of the (y+t2)-th frame.
Now the round starts. There will be E invaders in total, the ii-th of which will land at the starting point in the beginning of the ii-th frame of time. After that, any invader will take a step forward along the path in each frame of time. All invaders can be also divided into two kinds: privates and captains.
A private is the most inferior warrior with no special ability whose initial health point is HP1.
A captain is much more powerful whose initial health point is HP2, with some level defdef of defense capability. Once attacked by a defense tower whose damage point is damagedamage, he will suffer from max{1,damage−def} damage point. Note that attacks from different defense towers in any frame should be considered separately, but the damage caused by burning will not be considered as an attack within the defense capability.
An invader with health point less than zero is presumed dead and will be removed.
Let's make a summary of what will happen in a frame of time in this game.
The Enemy Step. All alive invaders take a step forward along the path. Then, a new invader may land at the starting point.
The Fire Step. All defense towers select their target. Then they fire together while those defense towers which have to target or wait for reloading ammunitions do nothing.
The Damage Estimation. Calculate the damage points and deduce the health points of all invaders. The burning damage will also be calculated at this time.
The Ending Step. All invaders with negative health points will be removed. If an alive invader is staying at the destination of the path, he invades the village successfully and will also be removed from the game.
Sheep has got some details about coming invaders, and he asks you to write a programme to simulate the game for the first T frames of time.
Input
The test data contains several test cases and the first line in input contains an integer Tcase (Tcase≤10) representing the number of test cases.
For every test case, The first line contains five integers n, k, L, En, k, L, E and T indicating the size of the map, the number of the defense towers, the length of the path, the number of invaders and the number of frames among your simulation. We guarantee that E≤T in all cases.
The following L lines describe the path. The i-th of them contains two integers xi and yi describing the coordinate of the i-th cell in the path. We guarantee that any two adjacent cells in the path share a common edge. The first cell locating at (x1, y1) is the starting point and the last cell locating at (xL, yL) is the destination where the village is.
The next line contains seven integers r1, d1, t1, r2, d2, t2 and d3 indicating all parameters about defense towers described as above. And then a line containing three integers HP1, HP2
and defdef describes parameters about invaders.
The next k lines describe all defense towers. The i-th of them contains three integers typei, xi
and yi where (xi, yi) is the coordinate of the i-th defense tower, and if typei=1 the tower is a gun tower, or a bunker if typei=2.
The last line contains a string of length E, the i-th digit in which describes the type of the ii-th invader where we use the character 1 to represent a private, and 2 to represent a captain.
All numbers in the input are positive integers and no more than 400.
Output
For the ii-th test case, output ‘Case \#i:’ (without quotes) in the first line. Then output E lines describing the final states of all invaders.
The ii-th line of them indicates the i-th invader:
If it will invade the village successfully, output ‘Arrive with Y HP(s).’ (without quotes) where Y represents his remaining HP.
If it will be killed in the t-th frame, output ‘Be killed in the t-th frame at (x,y).’ (without quotes), where (x,y) describes the location of his final resting place.
If this invader will live up to the T-th frame but not arrive at the village, output ‘Be alive at (x,y) with Y HP(s).’ (without quotes), where (x,y) represents his final coordinate in the T-th frame and Y represents his remaining HP.
渣翻一下:
最近,Sheep 被一个叫做“反抗”的塔防游戏深深吸引,但他现在被困在第 99 关不知所措,想让你伸出援助之手。
“反抗”是一款塔防游戏,地图为 n * n 的矩阵,有一条由一些单元组成的特定路径,任何两个相邻单元有一条公共边。我们保证路径不会通过同一个单元两次。村庄坐落在路径的终点,一些邪恶的侵略者会出生在出生点,沿着路径试图袭击村庄。
为了保卫村庄,Sheep 已经在地图上安置了 k 个防御塔攻击侵略者。所有防御塔被安置在路径和出生点以外的单元,且被分成两类:枪塔和地堡。
枪塔装备了一杆机枪,射程为 r1。一般情况下,它会选择范围内最近的敌军攻击,造成 d1 点伤害。如果同时有多个最近(欧几里得距离)敌军,则选择到达村庄需要步数最少的敌军攻击。题目保证不会出现违背上述条件的情况。完成一次攻击后,机枪进入 t1 秒冷却时间,即如果在第 x 秒攻击了,则从第 x + t1 秒起才能再次攻击。
地堡装备了燃烧弹,射程为 r2,没有冷却时间。它选择敌军的优先级判定和枪塔一致。每次攻击会造成 d2 点伤害,然后从下一秒开始敌军会开始燃烧,且每秒造成 d3 伤害,持续时间为 t2 秒,即如果在第 x 秒攻击了,则敌军会在第 x + t2 秒后停止燃烧。此外,如果一个燃烧中的敌军再次被地堡攻击,假设当时是第 y 秒,则燃烧时间延长至第 y + t2 秒。
现在开始游戏了!总共有 E 个侵略者,第 i 个会在第 i 秒出生在出生点。出生后,侵略者每秒回沿着给定路径走一个单元。侵略者分为两类:列兵和队长。
列兵没有任何特殊技能,初始生命值为 HP1。
队长初始生命值为 HP2,且拥有 def 点格挡。如果防御塔造成 damage 点伤害,他只会受到 max{1, damage - def} 点伤害。注意,任何时间的任何防御塔的每次攻击都是独立的。燃烧伤害不会被格挡。
如果一位侵略者的生命值小于 0,将会被判定为死亡且被移除。
现在来总结一下游戏中的每一秒发生了什么:
> 敌军环节。所有存活的侵略者将向前走一步。同时,可能有一个新的侵略者出生在出生点;
> 防御塔环节。所有没有进入冷却的防御塔选择它攻击的敌军并攻击;
> 伤害判定环节。计算所有侵略者受到的伤害,记得考虑燃烧伤害;
> 最后环节。所有生命值小于 0 的侵略者被移除。如果有存活的侵略者已经到达了村庄,则认为他成功袭击了村庄,然后被移除。
Sheep 现在得知了关于即将来临的侵略者的一些信息,他请求你编写个程序来模拟一下前 T 秒会发生什么。
输入
第一行一个整数 Tcase (Tcase <= 10),表示测试数据组数。
对于每一个测试数据:
第一行包含五个整数 n, k, L, E 和 T,分别表示地图大小,防御塔个数,路径长度,侵略者个数和模拟的秒数。 保证 E <= T。
接下来 L 行描述路径。第 i 行包含两个整数 xi 和 yi,表示路径的第 i 个单元的租表。我们保证任意两个相邻的单元有一条公共边。(x1, y1) 为出生点,(xL, yL) 为村庄位置。
接下来一行包含 7 个整数 r1, d1, t1, r2, d2, t2 和 d3,在防御塔部分介绍了它们的含义。
接下来一行包含 3 个整数 HP1, HP2 和 def,在敌军部分同样已经介绍了。
接下来 k 行描述防御塔。第 i 行包含三个整数 typei, xi 和 yi,表示第 i 个防御塔的类型和坐标,type = 1 表示是枪塔,反之为地堡。
最后一行包含一个长度为 E 的字符串,其第 i 个字符表示第 i 个侵略者的属性,1 表示列兵,2 表示队长。
输入数据中的所有数都是不超过 400 的正整数。
输出
对于第 i 个测试数据,先在第一行输出 "Case \#i"(不包括引号),接下来输出 E 行表示最终所有侵略者的状态,第 i 行表示第 i 个侵略者:
> 如果他成功袭击村庄,输出 "Arrive with Y HP(s).",其中 Y 表示他的剩余生命值;
> 如果他在第 t 秒被击杀了,输出 "Be killed in the t-th frame at (x,y).",其中 (x, y) 表示他被击杀的坐标;
> 如果他在第 T 秒未到达村庄且依然存活,输出 "Be alive at (x,y) with Y HP(s).",其中 (x, y) 表示他的最终坐标,Y 表示他的剩余生命值。
看题面就知道是一道很爽的题呢。
模拟题要出现在级别比较高的比赛中,往往具备如下特点:
细节多,操作繁杂,代码量大。
它一般不需要储备什么算法知识,也不需要用到数据结构,所以在思维上就要弱其他题型一等,所以出题人往往会在其他方面加大马力,比如增加大量的操作步骤,或者套入一个引人入胜的故事来让你沉迷情节无法自拔增加对题目关键部分的提炼难度。从亲身体会上来看,考场/赛场上做模拟题做难的地方并非编程,而是调试——因为代码量大,且大多是各种分支循环结构的嵌套,一旦花了大功夫写完整个程序长舒一口气再代入样例发现答案不对的时候心里就要咯噔一下;然后又花大功夫终于发现代码里一个 i 写成了 j 马上改了然后样例对了长舒一口气再提交一发结果一个红红的 WA 映入眼帘的时候更是心态崩溃,而如此往复若干次却死都找不到问题所在就会进入一个心态爆炸和找不到问题的恶性循环(为什么我要拿着这道题吐槽这么多?)
下面给出一些关于做大型模拟题的建议:
1、切忌直接开始码代码。认真读题,理清主干,先画出大概的流程图;
2、根据流程图的主干和分支,尽量将代码切割成若干子问题,操作主体多定义成类或结构体,操作过程多定义成子函数,且名称尽量能在一片混乱中能一眼分辨其定义和作用;
3、待补充。
最后给出例题代码:
(其实现在还没 A 掉,没有数据太难受了