HPCC2025/greedy_solver.py
2025-03-12 11:33:35 +08:00

238 lines
8.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.

import math
import yaml
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import numpy as np
def calculate_max_photos_per_flight(params):
"""计算每次飞行能拍摄的最大照片数量
基于以下约束:
1. 电池能量约束
2. 计算+传输时间 = 飞行时间
"""
# 从参数中提取时间和能量因子
flight_time_factor = params['flight_time_factor']
comp_time_factor = params['comp_time_factor']
trans_time_factor = params['trans_time_factor']
battery_energy_capacity = params['battery_energy_capacity']
flight_energy_factor = params['flight_energy_factor']
comp_energy_factor = params['comp_energy_factor']
trans_energy_factor = params['trans_energy_factor']
# 基于时间约束求解rho飞行时间 = 计算时间 + 传输时间
# flight_time_factor * d = comp_time_factor * rho * d + trans_time_factor * (1-rho) * d
rho_time = (flight_time_factor - trans_time_factor) / (comp_time_factor - trans_time_factor)
# 基于能量约束求解最大照片数d
# battery_energy_capacity = flight_energy_factor * d + comp_energy_factor * rho * d + trans_energy_factor * (1-rho) * d
energy_per_photo = (flight_energy_factor +
comp_energy_factor * rho_time +
trans_energy_factor * (1 - rho_time))
max_photos = math.floor(battery_energy_capacity / energy_per_photo)
return max_photos, rho_time
def solve_greedy(params):
"""使用贪心算法求解任务分配问题"""
H = params['H']
W = params['W']
k = params['num_cars'] # 系统数量
car_time_factor = params['car_time_factor']
bs_time_factor = params['bs_time_factor']
flight_time_factor = params['flight_time_factor']
# 计算每次飞行能拍摄的最大照片数
photos_per_flight, rho = calculate_max_photos_per_flight(params)
print(f"贪心无人机计算的情况下,每次飞行能拍摄的最大照片数: {photos_per_flight}")
print(f"卸载率 rho: {rho:.3f}")
# 用较小的边长来划分网格
min_side = min(H, W)
next_side = photos_per_flight // min_side
# 初始化任务分配列表
tasks = [[] for _ in range(k)]
if min_side == H:
grid_h = min_side
grid_w = next_side
num_rows = 1
num_cols = round(W / grid_w)
current_col = 0
for i in range(math.ceil(num_cols / k)):
for j in range(k):
tasks[j].append((0, current_col))
current_col += 1
if current_col == num_cols:
break
else:
grid_w = min_side
grid_h = next_side
num_cols = 1
num_rows = round(H / grid_h)
current_row = 0
for i in range(math.ceil(num_rows / k)):
for j in range(k):
tasks[j].append((current_row, 0))
current_row += 1
if current_row == num_rows:
break
print(f"网格大小: {grid_w}x{grid_h}")
print(f"网格数量: {num_rows}x{num_cols}")
print(f"任务分配情况: {tasks}")
# 计算区域中心点
center_x = W / 2
center_y = H / 2
# 为每个系统计算完成时间
system_times = []
for i in range(k):
if not tasks[i]: # 如果该系统没有分配任务
system_times.append(0)
continue
# 生成该系统负责的网格中心坐标
grids = []
for row, col in tasks[i]:
if min_side == H:
# 如果H是较小边那么row=0col递增
# TODO 最后一个网格的中心点不能这么算
grid_center_x = (col + 0.5) * grid_w
grid_center_y = (row + 0.5) * grid_h
else:
# 如果W是较小边那么col=0row递增
grid_center_x = (col + 0.5) * grid_w
grid_center_y = (row + 0.5) * grid_h
grids.append((grid_center_x, grid_center_y))
# 计算车辆路径长度(从中心点出发)
car_distance = math.hypot(center_x - grids[0][0], center_y - grids[0][1]) # 从中心到第一个网格
for j in range(len(grids)-1):
car_distance += math.hypot(grids[j+1][0] - grids[j][0],
grids[j+1][1] - grids[j][1]) # 网格间距离
car_distance += math.hypot(grids[-1][0] - center_x,
grids[-1][1] - center_y) # 从最后一个网格回到中心
# 计算时间
num_photos = len(grids) * photos_per_flight # 该系统需要拍摄的总照片数
flight_time = flight_time_factor * num_photos # 飞行时间
car_time = car_time_factor * car_distance # 车辆移动时间
bs_time = bs_time_factor * (1 - rho) * num_photos # 基站计算时间
total_time = max(flight_time + car_time, bs_time)
system_times.append(total_time)
print(f"\n系统 {i} 详细信息:")
print(f"负责的网格数: {len(grids)}")
print(f"总照片数: {num_photos}")
print(f"车辆移动距离: {car_distance:.2f}")
print(f"飞行时间: {flight_time:.2f}")
print(f"车辆时间: {car_time:.2f}")
print(f"基站时间: {bs_time:.2f}")
print(f"总完成时间: {total_time:.2f}")
# 找出最大完成时间
max_time = max(system_times)
print(f"\n最大完成时间: {max_time:.2f}")
# 准备返回结果
result = {
'max_time': max_time,
'system_times': system_times,
'photos_per_flight': photos_per_flight,
'grid_w': grid_w,
'grid_h': grid_h,
'num_rows': num_rows,
'num_cols': num_cols,
'tasks': tasks,
'rho': rho
}
return result
def plot_results(params, result):
"""可视化结果"""
H = params['H']
W = params['W']
k = params['num_cars']
plt.rcParams['font.family'] = ['sans-serif']
plt.rcParams['font.sans-serif'] = ['SimHei']
# 创建图形
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 5))
# 1. 绘制系统完成时间对比
ax1.bar(range(k), result['system_times'])
ax1.set_title('各系统完成时间对比')
ax1.set_xlabel('系统编号')
ax1.set_ylabel('完成时间(秒)')
# 2. 绘制网格划分示意图
ax2.set_xlim(0, W)
ax2.set_ylim(0, H)
# 为不同系统的网格使用不同颜色
colors = plt.cm.rainbow(np.linspace(0, 1, k))
# 绘制网格和系统分配
grid_w = result['grid_w']
grid_h = result['grid_h']
tasks = result['tasks']
# 绘制每个系统的网格
for system_idx, system_tasks in enumerate(tasks):
for row, col in system_tasks:
rect = patches.Rectangle(
(col * grid_w, row * grid_h),
grid_w, grid_h,
linewidth=1,
edgecolor='black',
facecolor=colors[system_idx],
alpha=0.3
)
ax2.add_patch(rect)
# 在网格中心添加系统编号
center_x = (col + 0.5) * grid_w
center_y = (row + 0.5) * grid_h
ax2.text(center_x, center_y, str(system_idx),
ha='center', va='center')
# 添加中心点标记
ax2.plot(W/2, H/2, 'r*', markersize=15, label='区域中心')
ax2.legend()
ax2.set_title('网格划分和系统分配示意图')
ax2.set_xlabel('宽度')
ax2.set_ylabel('高度')
plt.tight_layout()
plt.show()
def main():
# 读取参数
with open('params.yml', 'r', encoding='utf-8') as file:
params = yaml.safe_load(file)
# 求解
result = solve_greedy(params)
# 输出结果
print("\n求解结果:")
print(f"最大完成时间: {result['max_time']:.2f}")
print("\n各系统完成时间:")
for i, time in enumerate(result['system_times']):
print(f"系统 {i}: {time:.2f}")
# 可视化
plot_results(params, result)
if __name__ == "__main__":
main()