1 条题解

  • 0
    @ 2025-5-5 21:18:22

    算法标签

    回溯算法,贪心算法,图论

    问题描述

    猎人鲍勃带着他的狗拉尔夫沿着多边形路线散步。鲍勃以恒定速度行走,路线由N个顶点组成。拉尔夫可以在鲍勃移动时访问一些有趣的地方,但有以下限制:

    拉尔夫的速度最多是鲍勃的两倍

    在两个会合点之间最多只能访问一个有趣的地方

    每个有趣的地方最多被访问一次

    目标是找到拉尔夫能访问最多有趣地方的路线。

    解题思路

    方法选择 这个问题可以建模为一个图遍历问题,其中:

    节点是鲍勃的路径点和有趣的地方

    边表示狗可以在主人移动的同时完成的路径

    我们采用回溯算法结合贪心策略来解决这个问题,原因如下:

    问题规模较小(N,M100(N,M ≤ 100),回溯法可行

    需要尝试所有可能的兴趣点组合,回溯法适合这种组合搜索

    贪心策略可以帮助我们优先选择更有潜力的路径

    算法步骤

    预处理阶段:

    计算鲍勃每段路径的长度

    确定在每个路径段可以访问哪些兴趣点(满足速度限制)

    回溯搜索:

    从起点开始,尝试两种选择:

    直接前往下一个会合点

    绕道访问一个可行的兴趣点,再去会合点

    记录访问过的兴趣点,避免重复访问

    维护当前最优解

    剪枝优化:

    如果当前路径已不可能超过已知最优解,提前终止搜索

    优先尝试可能带来更多兴趣点的路径

    代码实现

    #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
    上传者