1 条题解
-
0
算法标签
回溯算法,贪心算法,图论
问题描述
猎人鲍勃带着他的狗拉尔夫沿着多边形路线散步。鲍勃以恒定速度行走,路线由N个顶点组成。拉尔夫可以在鲍勃移动时访问一些有趣的地方,但有以下限制:
拉尔夫的速度最多是鲍勃的两倍
在两个会合点之间最多只能访问一个有趣的地方
每个有趣的地方最多被访问一次
目标是找到拉尔夫能访问最多有趣地方的路线。
解题思路
方法选择 这个问题可以建模为一个图遍历问题,其中:
节点是鲍勃的路径点和有趣的地方
边表示狗可以在主人移动的同时完成的路径
我们采用回溯算法结合贪心策略来解决这个问题,原因如下:
问题规模较小,回溯法可行
需要尝试所有可能的兴趣点组合,回溯法适合这种组合搜索
贪心策略可以帮助我们优先选择更有潜力的路径
算法步骤
预处理阶段:
计算鲍勃每段路径的长度
确定在每个路径段可以访问哪些兴趣点(满足速度限制)
回溯搜索:
从起点开始,尝试两种选择:
直接前往下一个会合点
绕道访问一个可行的兴趣点,再去会合点
记录访问过的兴趣点,避免重复访问
维护当前最优解
剪枝优化:
如果当前路径已不可能超过已知最优解,提前终止搜索
优先尝试可能带来更多兴趣点的路径
代码实现
#include <iostream> #include <vector> #include <cmath> #include <algorithm> #include <unordered_set> #include <climits> #include <functional> using namespace std; struct Point { int x, y; Point(int x = 0, int y = 0) : x(x), y(y) {} bool operator==(const Point& other) const { return x == other.x && y == other.y; } }; namespace std { template<> struct hash<Point> { size_t operator()(const Point& p) const { return hash<int>()(p.x) ^ hash<int>()(p.y); } }; } double distance(const Point& a, const Point& b) { return sqrt(pow(a.x - b.x, 2) + pow(a.y - b.y, 2)); } bool canVisit(const Point& prev, const Point& next, const Point& dogPrev, const Point& dogNext, double bobDist) { double dogDist = distance(dogPrev, dogNext); return dogDist <= 2 * bobDist; } vector<Point> findOptimalRoute(int N, const vector<Point>& bobPath, int M, const vector<Point>& interesting) { vector<Point> bestRoute; int maxPoints = 0; // 预处理所有可能访问的兴趣点 vector<vector<int>> reachable(N); for (int i = 1; i < N; ++i) { double bobDist = distance(bobPath[i-1], bobPath[i]); for (int j = 0; j < M; ++j) { if (canVisit(bobPath[i-1], bobPath[i], bobPath[i-1], interesting[j], bobDist) && canVisit(interesting[j], bobPath[i], interesting[j], bobPath[i], distance(interesting[j], bobPath[i]))) { reachable[i].push_back(j); } } } // 使用回溯法尝试所有可能的兴趣点组合 vector<Point> currentRoute = {bobPath[0]}; unordered_set<int> visited; // 定义backtrack函数 function<void(int, int)> backtrack = [&](int pos, int points) { if (pos == N - 1) { if (points > maxPoints || (points == maxPoints && currentRoute.size() < bestRoute.size())) { maxPoints = points; bestRoute = currentRoute; } return; } // 不访问任何兴趣点 currentRoute.push_back(bobPath[pos + 1]); backtrack(pos + 1, points); currentRoute.pop_back(); // 尝试访问一个兴趣点 for (int j : reachable[pos + 1]) { if (visited.find(j) == visited.end()) { visited.insert(j); currentRoute.push_back(interesting[j]); currentRoute.push_back(bobPath[pos + 1]); backtrack(pos + 1, points + 1); currentRoute.pop_back(); currentRoute.pop_back(); visited.erase(j); } } }; backtrack(0, 0); return bestRoute; } int main() { int N, M; cin >> N >> M; vector<Point> bobPath(N); for (int i = 0; i < N; ++i) { cin >> bobPath[i].x >> bobPath[i].y; } vector<Point> interesting(M); for (int i = 0; i < M; ++i) { cin >> interesting[i].x >> interesting[i].y; } vector<Point> route = findOptimalRoute(N, bobPath, M, interesting); cout << route.size() << endl; for (size_t i = 0; i < route.size(); ++i) { if (i > 0) cout << " "; cout << route[i].x << " " << route[i].y; } cout << endl; return 0; }
- 1
信息
- ID
- 35
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 4
- 已通过
- 1
- 上传者