110 lines
4.1 KiB
Python
110 lines
4.1 KiB
Python
#-*-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) |