diff --git a/boss_fight.py b/boss_fight.py index 20f2f76..232c36c 100644 --- a/boss_fight.py +++ b/boss_fight.py @@ -1,136 +1,110 @@ -# -*-coding: GBK -*- -import heapq # 导入堆模块,用于实现优先队列 -from typing import List, Optional, Tuple # 导入类型提示相关模块 +#-*-coding: GBK -*- +import math +import heapq +def boss_fight(B, PlayerSkills): + n = len(B) + m = len(PlayerSkills) + if n == 0: + return [] + + # 计算最大平均伤害用于启发式函数 + max_avg = 0.0 + for a, b in PlayerSkills: + if b + 1 > 0: + avg = a / (b + 1) + if avg > max_avg: + max_avg = avg + # 如果所有技能伤害为0,则无法击败BOSS + if max_avg == 0: + return None + + # 初始状态:boss索引0,血量B[0],冷却全0,回合数0,路径空 + start_cooldown = tuple([0] * m) + total_remaining = sum(B) + #f_value = 当前回合数 + 估计剩余回合数 + f_value = math.ceil(total_remaining / max_avg) if max_avg > 0 else total_remaining -def boss_strategy(coin: int, blood: int) -> Optional[Tuple[List[str], int]]: - # 使用分支限界法寻找最小回合数击败BOSS的技能序列 + # 初始化优先队列 (f_value, round_count, boss_idx, boss_rem, cooldown, path) + queue = [(f_value, 0, 0, B[0], start_cooldown, [])] + # 记录访问过的状态(boss_idx, boss_rem, cooldown) -> 最小回合数 + visited = {} + visited[(0, B[0], start_cooldown)] = 0 + + all_path = [] + # 优先队列按f_value排序 + while queue: + # 优先扩展f_value最小的状态(最有希望的状态) + f_value, round_count, boss_idx, boss_rem, cooldown, path = heapq.heappop(queue) + + state_key = (boss_idx, boss_rem, cooldown) - # 参数: - # coin: 玩家初始金币数 - # blood: BOSS初始血量 - - # 返回: - # 最小回合数的技能序列列表,如果无解则返回None - - start_coin = coin # 记录初始金币数,用于计算消耗金币 - - # 初始状态: (回合数, 剩余金币, BOSS血量, 充能, 连续E计数, 技能序列元组) - start_state = (0, coin, blood, 0, 0, ()) - - # 创建优先队列: 元素为 (优先级, 状态) - # 优先级元组: (回合数, 消耗金币, BOSS血量) - 值越小优先级越高 - heap = [] - heapq.heappush(heap, ((0, 0, blood), start_state)) # 将初始状态加入优先队列 - - # 创建访问集合: 用于避免重复状态 - # 状态键: (回合数, 剩余金币, BOSS血量, 充能, min(连续E计数,3)) - visited = set() - start_ce_compressed = min(0, 3) # 压缩连续E计数状态 - visited.add((0, coin, blood, 0, start_ce_compressed)) # 将初始状态加入已访问集合 - - # 设置最大回合数限制,避免无限循环 - max_round = blood * 2 # 每次至少造成1点伤害,最多回合数为血量两倍 - - # 主循环: 处理优先队列中的状态 - while heap: - # 从优先队列中取出优先级最高的状态 - priority, state = heapq.heappop(heap) - # 解包状态元组 - round_cnt, cur_coin, cur_blood, energy, ce, seq_tuple = state - - # 检查是否已击败BOSS - if cur_blood <= 0: - return (list(seq_tuple), cur_coin) # 返回技能序列和剩余金币 - - # 超过最大回合数则跳过当前状态 - if round_cnt >= max_round: + # 状态检查:如果已有更好状态,跳过当前状态 + if visited.get(state_key, float('inf')) < round_count: continue - - # 尝试使用技能A - if cur_coin >= 2: # 检查金币是否足够 - new_coin = cur_coin - 2 # 扣除金币 - new_blood = cur_blood - 1 # 减少BOSS血量 - new_energy = energy + 1 # 增加充能 - new_ce = 0 # 使用非E技能,重置连续E计数 - new_round = round_cnt + 1 # 回合数+1 - new_seq = seq_tuple + ('A',) # 添加技能到序列 - - # 压缩连续E计数状态(>=3视为3) - ce_compressed = min(new_ce, 3) - # 创建状态键用于去重 - state_key = (new_round, new_coin, new_blood, new_energy, ce_compressed) - - # 检查是否为新状态 - if state_key not in visited: - visited.add(state_key) # 标记为已访问 - cost = start_coin - new_coin # 计算已消耗金币 - # 创建新状态 - new_state = (new_round, new_coin, new_blood, new_energy, new_ce, new_seq) - # 将新状态加入优先队列 - heapq.heappush(heap, ((new_round, cost, new_blood), new_state)) - - # 尝试使用技能E - cost_e = 3 # 默认消耗金币 - if ce >= 2: # 检查是否为连续第三次使用E - cost_e = 2 # 第三次消耗2金币 - - if cur_coin >= cost_e: # 检查金币是否足够 - new_coin = cur_coin - cost_e # 扣除金币 - new_blood = cur_blood - 3 # 减少BOSS血量 - new_energy = energy + 1 # 增加充能 - new_ce = ce + 1 # 增加连续E计数 - new_round = round_cnt + 1 # 回合数+1 - new_seq = seq_tuple + ('E',) # 添加技能到序列 - - # 压缩连续E计数状态 - ce_compressed = min(new_ce, 3) - # 创建状态键用于去重 - state_key = (new_round, new_coin, new_blood, new_energy, ce_compressed) - - # 检查是否为新状态 - if state_key not in visited: - visited.add(state_key) # 标记为已访问 - cost = start_coin - new_coin # 计算已消耗金币 - # 创建新状态 - new_state = (new_round, new_coin, new_blood, new_energy, new_ce, new_seq) - # 将新状态加入优先队列 - heapq.heappush(heap, ((new_round, cost, new_blood), new_state)) - - # 尝试使用技能Q - if energy >= 3 and cur_coin >= 3: # 检查充能和金币是否足够 - new_coin = cur_coin - 3 # 扣除金币 - new_blood = cur_blood - 8 # 减少BOSS血量 - new_energy = energy - 3 # 消耗充能 - new_ce = 0 # 使用非E技能,重置连续E计数 - new_round = round_cnt + 1 # 回合数+1 - new_seq = seq_tuple + ('Q',) # 添加技能到序列 - - # 压缩连续E计数状态 - ce_compressed = min(new_ce, 3) - # 创建状态键用于去重 - state_key = (new_round, new_coin, new_blood, new_energy, ce_compressed) - - # 检查是否为新状态 - if state_key not in visited: - visited.add(state_key) # 标记为已访问 - cost = start_coin - new_coin # 计算已消耗金币 - # 创建新状态 - new_state = (new_round, new_coin, new_blood, new_energy, new_ce, new_seq) - # 将新状态加入优先队列 - heapq.heappush(heap, ((new_round, cost, new_blood), new_state)) - - return None # 队列为空,无解 + + # 所有BOSS已击败 + if boss_idx >= n: + return path + + # 等待操作:所有冷却时间减1,回合数+1,路径添加-1 + new_cooldown_list = [max(0, c - 1) for c in cooldown] + new_cooldown = tuple(new_cooldown_list) + new_round = round_count + 1 + new_state_key = (boss_idx, boss_rem, new_cooldown) + # 若新状态更优,则加入队列 + if new_state_key not in visited or visited[new_state_key] > new_round: + visited[new_state_key] = new_round + total_remaining = boss_rem + sum(B[boss_idx+1:]) + estimate_rounds = math.ceil(total_remaining / max_avg) if max_avg > 0 else 0 + new_f = new_round + estimate_rounds + new_path = path + [-1] + heapq.heappush(queue, (new_f, new_round, boss_idx, boss_rem, new_cooldown, new_path)) + + # 使用技能 + for skill_idx, (a, b) in enumerate(PlayerSkills): + if cooldown[skill_idx] != 0: # 技能不可用 + continue + + new_boss_idx = boss_idx + new_boss_rem = boss_rem - a + + # 击败当前BOSS + if new_boss_rem <= 0: + new_boss_idx += 1 + all_path.append(new_path) + new_path = [] + if new_boss_idx < n: + new_boss_rem = B[new_boss_idx] # 切换至下一个BOSS + else: + new_boss_rem = 0 # 所有BOSS已击败 + + # 更新冷却时间 + new_cooldown_list = [max(0, c - 1) for c in cooldown] + new_cooldown_list[skill_idx] = b # 重置当前技能冷却时间 + new_cooldown = tuple(new_cooldown_list) + new_round = round_count + 1 + new_path = path + [skill_idx] + + # 所有BOSS已击败,返回路径 + if new_boss_idx >= n: + return all_path + + new_state_key = (new_boss_idx, new_boss_rem, new_cooldown) + # 若新状态更优,则加入队列 + if new_state_key not in visited or visited[new_state_key] > new_round: + visited[new_state_key] = new_round + total_remaining = new_boss_rem + sum(B[new_boss_idx+1:]) + estimate_rounds = math.ceil(total_remaining / max_avg) if max_avg > 0 else 0 + new_f = new_round + estimate_rounds + heapq.heappush(queue, (new_f, new_round, new_boss_idx, new_boss_rem, new_cooldown, new_path)) + + return None # 无解 -# 主程序入口 -if __name__ == "__main__": - # 测试示例: 金币=10, BOSS血量=10 - result = boss_strategy(20, 20) - - if result is None: - print("无法击败BOSS") - else: - skill_sequence, remaining_coins = result - print("最小回合数技能序列:", skill_sequence) # 预期输出: ['A', 'A', 'A', 'Q'] - print("剩余金币:", remaining_coins) # 预期输出: 1 +if __name__ == '__main__': + B = [10, 20, 30, 40, 50] + PlayerSkills = [(5, 2), (8, 3), (3, 1)] + ans = boss_fight(B, PlayerSkills) + for i in ans: + print(i) \ No newline at end of file