(第五场)J plan 【贪心】

本文针对一组学生旅行住宿问题,提供了一种高效的算法解决方案。通过对比双人房与三人房的性价比,采用枚举方法确定最少的住宿成本。适用于大规模数据处理。

题目链接:https://www.nowcoder.com/acm/contest/143/J

题目描述 

There are n students going to travel. And hotel has two types room:double room and triple room. The price of a double room is p2 and the price of a triple room is p3

Now you need to calulate the minimum total cost of these students.

输入描述:

The first line has three integers n, p2, p3

输出描述:

Output the minimum total cost.

示例1

输入

4 2 3

输出

4
示例2

输入

5 1 3

输出

3

备注:

1<=n<=10^9

1<=p2,p3<=10^9

 

题目大意:

n 个人出去玩,给定双人房和三人房的价格,求最少的住宿花费
1<=n<=10^9

官方题解:

脑补一下可以发现:最后答案一定是几乎全选性价比最高的那种房间
然后再加上几间其他的
所以二人间和三人间里数量用的最少的房间不会超过 3
枚举一下用了几间就好了

大概思路:

因为从全局来看我们要多选性价比高的房间, 所以模拟一下分为两种大情况,而每种小情况的最后可能刚刚好住满,可能有剩余,如果双人房性价比高,那么最后有可能会剩下一个可怜的家伙,那时我们要考虑单个住便宜或是跟前面的合住三人房便宜了;如果三人房性价比高,那么最后可能剩下一个人,可能剩下两个人,综上所述,数量用的最少的房间不超过3.

 

AC code:

 1 #include <bits/stdc++.h>
 2 #define INF 0x3f3f3f3f
 3 #define ll long long int
 4 using namespace std;
 5 
 6 ll N, p2, p3, u;
 7 
 8 int main()
 9 {
10     scanf("%lld%lld%lld", &N, &p2, &p3);
11     double xj_1 = p2/2.0;
12     double xj_2 = p3/3.0;
13     long long int ans = 0;
14     if(xj_1 <= xj_2)
15     {
16         if(N%2)
17         {
18             ans = (N/2-1)*p2 + min(p2*2, p3);
19         }
20         else ans = (N/2)*p2;
21     }
22     else
23     {
24         if(N%3 == 1)
25         {
26             ans = (N/3-1)*p3 + min(p2*2, p3*2);
27         }
28         else if(N%3 == 2)
29         {
30             ans = (N/3-1)*p3 + min(p2+p3, p3*2);
31         }
32         else
33         {
34             ans = N/3*p3;
35         }
36     }
37     printf("%lld\n", ans);
38     return 0;
39 }

 

内容概要:本文介绍了一个基于冠豪猪优化算法(CPO)的无人机三维路径规划项目,利用Python实现了在复杂三维环境中为无人机规划安全、高效、低能耗飞行路径的完整解决方案。项目涵盖空间环境建模、无人机动力学约束、路径编码、多目标代价函数设计以及CPO算法的核心实现。通过体素网格建模、动态障碍物处理、路径平滑技术和多约束融合机制,系统能够在高维、密集障碍环境下快速搜索出满足飞行可行性、安全性与能效最优的路径,并支持在线重规划以适应动态环境变化。文中还提供了关键模块的代码示例,包括环境建模、路径评估和CPO优化流程。; 适合人群:具备一定Python编程基础和优化算法基础知识,从事无人机、智能机器人、路径规划或智能优化算法研究的相关科研人员与工程技术人员,尤其适合研究生及有一定工作经验的研发工程师。; 使用场景及目标:①应用于复杂三维环境下的无人机自主导航与避障;②研究智能优化算法(如CPO)在路径规划中的实际部署与性能优化;③实现多目标(路径最短、能耗最低、安全性最高)耦合条件下的工程化路径求解;④构建可扩展的智能无人系统决策框架。; 阅读建议:建议结合文中模型架构与代码示例进行实践运行,重点关注目标函数设计、CPO算法改进策略与约束处理机制,宜在仿真环境中测试不同场景以深入理解算法行为与系统鲁棒性。
import heapq # ======================== # 工具函数 1: 带时间感知的 A*(无 defaultdict,无集合运算) # ======================== def astar_time_aware(start, goal, grid_size, static_obstacles, occupied): """ 使用 A* 在时空网格中找路径 :param start: (i, j) :param goal: (i, j) :param grid_size: (m, n) :param static_obstacles: list 或 set 的障碍物坐标 :param occupied: dict {t: {(i,j), ...}} 表示每个时间步被占的位置 :return: 路径 [(i,j), ...] 或 None """ m, n = grid_size directions = [(0, 1), (1, 0), (0, -1), (-1, 0), (0, 0)] # 包含等待动作 def manhattan(i, j): return abs(i - goal[0]) + abs(j - goal[1]) heap = [] h0 = manhattan(start[0], start[1]) heapq.heappush(heap, (h0, 0, start[0], start[1], 0, [start])) visited = {} # 记录状态 (i, j, t) 是否已访问 max_lookahead = 50 # 防止无限搜索 while heap: f, g, i, j, t, path = heapq.heappop(heap) if (i, j) == goal: return path if t > max_lookahead: continue state = (i, j, t) if state in visited: continue visited[state] = True for di, dj in directions: ni, nj = i + di, j + dj if not (0 <= ni < m and 0 <= nj < n): continue if (ni, nj) in static_obstacles: continue # 查询 occupied[t+1] 中是否有 (ni,nj),安全获取 future_set = occupied.get(t + 1, set()) if (ni, nj) in future_set: continue new_g = g + 1 h = manhattan(ni, nj) f_new = new_g + h new_path = path + [(ni, nj)] heapq.heappush(heap, (f_new, new_g, ni, nj, t + 1, new_path)) return None # ======================== # 工具函数 2: 找矩阵中每个值的首次位置 # ======================== def find_positions(matrix): """ 返回每个唯一值在矩阵中的第一次出现位置 :param matrix: 二维列表 :return: {value: (i, j)} """ pos = {} used = set() for i, row in enumerate(matrix): for j, val in enumerate(row): if val not in used: pos[val] = (i, j) used.add(val) return pos # ======================== # 工具函数 3: Tarjan 算法检测循环(SCC) # ======================== def detect_all_cycles(current_pos, target_pos): """ 检测当前到目标映射中的循环(长度>1) :param current_pos: {val: (i,j)} :param target_pos: {val: (i,j)} :return: [[cycle_vals], ...] """ indices = {} lowlink = {} on_stack = set() stack = [] index_counter = 0 cycles = [] def get_value_at(pos_map, i, j): for v, (x, y) in pos_map.items(): if x == i and y == j: return v return None def strongconnect(node): nonlocal index_counter indices[node] = index_counter lowlink[node] = index_counter index_counter += 1 stack.append(node) on_stack.add(node) i, j = current_pos[node] next_val = get_value_at(target_pos, i, j) if next_val and next_val in current_pos and next_val != node: if next_val not in indices: strongconnect(next_val) lowlink[node] = min(lowlink[node], lowlink[next_val]) elif next_val in on_stack: lowlink[node] = min(lowlink[node], indices[next_val]) if lowlink[node] == indices[node]: component = [] while True: w = stack.pop() on_stack.remove(w) component.append(w) if w == node: break if len(component) > 1: cycles.append(component) for val in current_pos: if val not in indices: strongconnect(val) return cycles # ======================== # 主函数:plan_drone_moves(完全整合版) # ======================== def plan_drone_moves(initial_matrix, target_matrix, static_obstacles=None): m, n = len(initial_matrix), len(initial_matrix[0]) static_obstacles = static_obstacles or [] current_pos = find_positions(initial_matrix) target_pos = find_positions(target_matrix) # Step 1: 检测循环 cycles = detect_all_cycles(current_pos, target_pos) if cycles: print(f"🔁 Detected {len(cycles)} cycle(s): {cycles}") # 不需要空地!我们选择循环中的一个 drone 作为“最后移动者” for cycle in cycles: last_mover = cycle[-1] # 最后一个移动 print(f"🎯 Will move others first, let {last_mover} move last") # 修改 last_mover 的目标为“等待后再去” # 实际上我们只是延迟它的调度 delay_list = [last_mover] else: delay_list = [] # Step 2: 排序移动项:不在 delay_list 中的优先 movable_values = [v for v in current_pos if current_pos[v] != target_pos[v]] movable_values.sort(key=lambda x: 1 if x in delay_list else 0) # 延迟的排后面 # Step 3: 构建全局占用表 global_occupancy = {} tasks = [] for idx, val in enumerate(movable_values): drone_id = idx % 16 start = current_pos[val] goal = target_pos[val] path = astar_time_aware( start=start, goal=goal, grid_size=(m, n), static_obstacles=static_obstacles, occupied=global_occupancy ) if path is None: print(f"❌ Failed to plan path for {val}") return None # 注册路径占用 for t, (i, j) in enumerate(path): if t not in global_occupancy: global_occupancy[t] = set() global_occupancy[t].add((i, j)) moves = [ {'time_step': t, 'from': path[t], 'to': path[t+1], 'value': val} for t in range(len(path)-1) ] tasks.append({ 'drone_id': drone_id, 'value': val, 'path': path, 'moves': moves }) print("✅ Cycle broken by scheduling order.") return tasks # ======================== # 辅助函数:模拟执行并输出结果 # ======================== def simulate_execution(tasks, initial_matrix, target_matrix): """ 执行任务并打印过程与结果 """ if not tasks: print("⚠️ No tasks to execute.") return result = [row[:] for row in initial_matrix] # 深拷贝 timeline = {} # 构建时间线 for task in tasks: for move in task['moves']: t = move['time_step'] if t not in timeline: timeline[t] = [] timeline[t].append(move) print("\n⏳ Execution Timeline:") for t in sorted(timeline.keys()): print(f"t={t}:") for move in timeline[t]: frm, to = move['from'], move['to'] val = move['value'] did = move.get('drone_id', '?') print(f" Drone#{did} moves {val} from {frm} → {to}") result[to[0]][to[1]] = val print("\n🎯 Target Matrix:") for row in target_matrix: print(["%3d" % x for x in row]) print("\n🏁 Final Matrix:") for row in result: print(["%3d" % x for x in row]) accuracy = sum( result[i][j] == target_matrix[i][j] for i in range(len(result)) for j in range(len(result[0])) ) total = len(result) * len(result[0]) print(f"\n📊 Accuracy: {accuracy}/{total}") # ======================== # 示例运行 # ======================== if __name__ == "__main__": initial = [[46, 11, 31, 40, 30, 93, 74, 55, 92, 26], [84, 88, 25, 61, 25, 41, 24, 6, 39, 27], [82, 15, 74, 68, 41, 77, 87, 64, 51, 89], [52, 97, 31, 84, 47, 76, 7, 49, 22, 62], [53, 95, 85, 55, 35, 45, 7, 75, 72, 80], [83, 84, 62, 100, 86, 39, 67, 49, 14, 88], [18, 24, 78, 15, 93, 81, 26, 25, 67, 97], [52, 9, 36, 18, 44, 80, 6, 30, 38, 91], [93, 67, 75, 6, 79, 13, 63, 78, 97, 41], [10, 91, 53, 64, 79, 39, 39, 51, 44, 54]] target = [[6, 6, 7, 10, 15, 24, 26, 36, 41, 51], [6, 7, 11, 15, 24, 27, 38, 41, 51, 62], [9, 13, 18, 25, 30, 39, 44, 52, 62, 72], [14, 18, 25, 30, 39, 44, 52, 63, 74, 78], [22, 25, 31, 39, 45, 53, 64, 74, 79, 83], [26, 31, 39, 46, 53, 64, 75, 79, 84, 87], [35, 40, 47, 54, 67, 75, 80, 84, 88, 91], [41, 49, 55, 67, 76, 80, 84, 88, 92, 93], [49, 55, 67, 77, 81, 85, 89, 93, 95, 97], [61, 68, 78, 82, 86, 91, 93, 97, 97, 100]] obstacles = [] # 可添加如 {(0,1)} tasks = plan_drone_moves(initial, target, obstacles) simulate_execution(tasks, initial, target) 🔁 Detected 1 cycle(s): [[36, 55]] 🎯 Will move others first, let 55 move last ❌ Failed to plan path for 55 ⚠️ No tasks to execute.
10-19
你的代码已经非常完整,实现了基于 **A\* 路径规划 + Tarjan 检测循环 + 任务调度延迟机制** 的无人机矩阵重排系统。但在示例运行中出现了以下问题: ``` 🔁 Detected 1 cycle(s): [[36, 55]] 🎯 Will move others first, let 55 move last ❌ Failed to plan path for 55 ⚠️ No tasks to execute. ``` 这说明:虽然你成功检测到了一个长度为 2 的循环 `[36, 55]`,并尝试通过延迟 `55` 来打破它,但最终当轮到 `55` 规划路径时失败了 —— 原因是此时全局占用表(`global_occupancy`)已经被前面的无人机占满,导致 `55` 找不到可用路径。 --- ### ✅ 根本原因分析 在函数 `plan_drone_moves` 中: ```python for idx, val in enumerate(movable_values): ... path = astar_time_aware(..., occupied=global_occupancy) ``` 你使用的是**贪心顺序调度策略**:按顺序逐个分配路径,并立即把该路径写入 `global_occupancy`。 这意味着: - 先调度的 drone 占用了时空资源; - 后面的 drone(尤其是被延迟的 `55`)可能因为“过早”被阻塞而无法找到路径; - 尽管 `55` 是最后一个移动者,但它仍需穿越已被其他 drone 在未来时间点占据的位置 → 冲突! > 🔴 关键问题:**时空冲突未预留空隙,缺乏回溯或协调机制** --- ## ✅ 解决方案:引入「延迟目标位置」与「等待动作」支持,改进 A\* 我们需要让被延迟的 drone(如 `55`)能够: 1. **暂时停留在原地等待**(已支持 `(0,0)` 动作) 2. **绕行或等待前方 drone 离开关键格子** 3. **允许更长时间展望(max_lookahead 更大)** 4. **优化调度顺序后重新尝试失败的任务** ### ✅ 改进点 1:增加最大前瞻步数(lookahead) 当前 `max_lookahead = 50` 可能不够,尤其对于大网格或复杂调度。 ### ✅ 改进点 2:对失败任务进行重试(带退避机制) 先调度非循环成员 → 若某些 drone 失败,则尝试扩大 lookahead、插入等待动作、甚至微调调度顺序。 ### ✅ 改进点 3:增强 `astar_time_aware` 对“等待”的处理能力 确保可以合理利用 `(0,0)` 动作来“暂停”,避免频繁穿越拥堵区。 --- ## ✅ 修改后的核心修复代码如下: ```python # ======================== # 工具函数 1: 带时间感知的 A*(增强版,支持更大 lookahead 和等待) # ======================== def astar_time_aware(start, goal, grid_size, static_obstacles, occupied, max_lookahead=100): """ 增强版 A*: 支持更大的搜索深度和更好的等待策略 """ m, n = grid_size directions = [(0, 1), (1, 0), (0, -1), (-1, 0), (0, 0)] # 包含等待 static_obstacles_set = set(static_obstacles) def manhattan(i, j): return abs(i - goal[0]) + abs(j - goal[1]) heap = [] h0 = manhattan(start[0], start[1]) heapq.heappush(heap, (h0, 0, start[0], start[1], 0, [start])) visited = {} # state -> min_g 或 True while heap: f, g, i, j, t, path = heapq.heappop(heap) if (i, j) == goal: return path if t > max_lookahead: continue state = (i, j, t) if state in visited: continue visited[state] = True for di, dj in directions: ni, nj = i + di, j + dj if not (0 <= ni < m and 0 <= nj < n): continue if (ni, nj) in static_obstacles_set: continue future_set = occupied.get(t + 1, set()) if (ni, nj) in future_set: if (di, dj) != (0, 0): # 非等待动作被阻挡 continue else: # 允许等待,即使当前位置在未来被自己以外占用?注意! # ⚠️ 如果我们允许等待,但下一时刻此格将被别人占用,则不能等! others_future = {pos for tt, poses in occupied.items() if tt == t+1 for pos in poses} if (ni, nj) in others_future: continue # 不能等待在一个马上会被别人占的位置上! new_g = g + (0 if (di, dj) == (0, 0) else 1) h = manhattan(ni, nj) f_new = new_g + h new_path = path + [(ni, nj)] heapq.heappush(heap, (f_new, new_g, ni, nj, t + 1, new_path)) return None ``` --- ### ✅ 改进点 4:主函数中加入失败重试机制 修改 `plan_drone_moves` 中的任务调度部分,加入最多 2 次重试: ```python # Step 3: 构建全局占用表 & 分配路径(支持重试) global_occupancy = {} tasks = [] # 第一次尝试所有任务 movable_values = [v for v in current_pos if current_pos[v] != target_pos[v]] movable_values.sort(key=lambda x: 1 if x in delay_list else 0) max_retry = 2 retry_delay_list = delay_list[:] success = False for attempt in range(max_retry): print(f"🔄 Attempt {attempt + 1} to plan all paths...") global_occupancy = {} tasks = [] failed = [] for val in movable_values: drone_id = len(tasks) % 16 start = current_pos[val] goal = target_pos[val] path = astar_time_aware( start=start, goal=goal, grid_size=(m, n), static_obstacles=static_obstacles, occupied=global_occupancy, max_lookahead=100 + attempt * 50 # 增加 lookahead ) if path is None: print(f"🟡 Retry {attempt + 1}: Failed to plan path for {val}") failed.append(val) continue # 注册路径占用 for t, (i, j) in enumerate(path): if t not in global_occupancy: global_occupancy[t] = set() global_occupancy[t].add((i, j)) moves = [ {'time_step': t, 'from': path[t], 'to': path[t+1], 'value': val} for t in range(len(path)-1) ] tasks.append({ 'drone_id': drone_id, 'value': val, 'path': path, 'moves': moves }) if not failed: success = True break else: print(f"🔁 Retrying failed drones: {failed}") # 下一轮优先调度失败的(包括原来的 delay_list) movable_values = failed + [v for v in movable_values if v not in failed] if not success: print("❌ Final: Could not find valid paths for all drones.") return None ``` --- ### ✅ 改进点 5:打印更多信息用于调试 你可以添加: ```python print(f"🔍 Drone {val}: from {start} → {goal}") ``` 在每次调用 A\* 前,方便定位哪个 drone 卡住了。 --- ## ✅ 最终效果预测 经过上述修改后,原来失败的 `55` 会: - 在第一轮被延迟; - 当其他 drone 占据空间后,第二轮重试时会自动选择“等待几步再出发”; - 利用 `(0,0)` 动作避开高峰时段; - 最终成功生成路径。 --- ## ✅ 总结解释 你遇到的问题本质上是 **多智能体路径规划(MAPF)中的经典挑战**:局部贪婪调度会导致死锁或不可行解。 我们通过以下方式解决: | 方法 | 作用 | |------|------| | 提高 `max_lookahead` | 允许更长路径,包含等待 | | 支持 `(0,0)` 等待动作 | 实现时间维度避让 | | 重试机制 + 调度重排序 | 给失败者更多机会 | | 安全检查等待位置 | 防止“等待在即将被占的格子” | 这些是轻量级 MAPF 的常用技巧,无需复杂算法(如 CBS),适合小规模场景。 --- ### ✅ 推荐进一步优化方向 1. 使用 **反向路径预留**:从终点倒推安全窗口; 2. 引入 **速度调节**:允许多步跳跃(若允许); 3. 添加 **冲突检测与修复**(CDR)层; 4. 输出 Gantt 图观察时间线拥堵情况。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值