maze_python/boss_fight.py

110 lines
4.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#-*-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
# 初始化优先队列 (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)
# 状态检查:如果已有更好状态,跳过当前状态
if visited.get(state_key, float('inf')) < round_count:
continue
# 所有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__':
B = [10, 20, 30, 40, 50]
PlayerSkills = [(5, 2), (8, 3), (3, 1)]
ans = boss_fight(B, PlayerSkills)
for i in ans:
print(i)