C++ 笔试算法实战:打怪模拟、字符串分类与连通分量
最近整理了几道经典的 C++ 笔试算法题,涵盖数学模拟、字符串处理和图论搜索。直接上干货,看看这些题目背后的核心逻辑。
一、打怪问题
题目描述
我们需要击败一系列毛球怪。我方属性为血量 h 和攻击 a,怪物属性为血量 H 和攻击 A。双方轮流攻击,我先手。当血量小于等于 0 时死亡。求在存活的前提下,最多能杀死多少只怪物?如果无限多,输出 -1。
解题思路
这道题看似需要模拟战斗过程,但数据量大时模拟会超时。既然每个怪物的属性固定,我们可以计算击杀一只怪物所需的代价。
- 计算击杀次数:要杀死一只血量为
H的怪物,需要攻击次数k = ceil(H / a)。 - 计算承受伤害:因为先手,当我方打出第
k击怪物死亡后,对方没有机会反击。所以实际受到攻击的次数是k - 1。单次击杀承受伤害cost = (k - 1) * A。 - 判断无限情况:如果我的攻击力
a >= H,可以一击必杀且自身不掉血,此时答案为-1。 - 计算最大数量:总血量
h除以单次代价cost。注意边界条件,如果h能被cost整除,说明打完最后一击后血量刚好归零,不算存活,结果需减 1。
代码实现
#include <iostream>
using namespace std;
int h, a, H, A;
int solve() {
// 如果一击必杀,则无伤通关,数量无限
if (H <= a) return -1;
// 计算需要攻击多少次才能杀死一只怪
int hits_needed = H / a + (H % a == 0 ? 0 : 1);
// 先手优势:我们攻击 hits_needed 次,怪物只能反击 hits_needed - 1 次
int damage_per_monster = (hits_needed - 1) * A;
// 计算能杀多少只
int count = h / damage_per_monster;
// 如果血量刚好被消耗完(整除),说明最后一只没活下来,减 1
(h % damage_per_monster == ) {
count--;
}
count;
}
{
t;
cin >> t;
(t--) {
cin >> h >> a >> H >> A;
cout << () << endl;
}
;
}


