1 条题解

  • 0
    @ 2025-7-18 11:42:45
    #include <iostream>
    #include <vector>
    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    
    const double eps = 1e-6;
    const int SECONDS_PER_DAY = 86400;
    
    // 将时间字符串转换为秒数
    int str_to_seconds(const string& s) {
        int h, m, sec;
        sscanf(s.c_str(), "%d:%d:%d", &h, &m, &sec);
        return h * 3600 + m * 60 + sec;
    }
    
    // 比较两个路径的字典序
    bool greater_path(const vector<int>& a, const vector<int>& b) {
        for (int i = 0; i < a.size() && i < b.size(); i++) {
            if (a[i] != b[i]) {
                return a[i] > b[i];
            }
        }
        return false; // 相等
    }
    
    // 检查从码头i到码头j在第day天是否可行
    bool check_feasible(int day, int i, int j, const vector<double>& dists, const vector<int>& inaccess,
                       double speed, int sunrise0, int sunrise_interval, int sunset0, int sunset_interval,
                       int tide0, int tide_interval) {
        // 计算第day天的日出和日落时间(相对当天00:00:00)
        double sunrise_d = (sunrise0 + (day - 1) * (double)sunrise_interval);
        sunrise_d = fmod(sunrise_d, SECONDS_PER_DAY);
        if (sunrise_d < 0) sunrise_d += SECONDS_PER_DAY;
    
        double sunset_d = (sunset0 + (day - 1) * (double)sunset_interval);
        sunset_d = fmod(sunset_d, SECONDS_PER_DAY);
        if (sunset_d < 0) sunset_d += SECONDS_PER_DAY;
    
        // 计算第day天的低潮事件(相对当天00:00:00)
        vector<double> tides;
        double start_abs = (day - 1) * (double)SECONDS_PER_DAY;
        double end_abs = day * (double)SECONDS_PER_DAY;
    
        // 计算k的范围
        double k_min = ceil((start_abs - tide0) / tide_interval);
        if (k_min < 0) k_min = 0;
        double k_max = floor((end_abs - tide0 - 1) / tide_interval);
    
        for (int k = k_min; k <= k_max; k++) {
            double t_abs = tide0 + k * (double)tide_interval;
            if (t_abs >= start_abs && t_abs < end_abs) {
                double t_rel = t_abs - start_abs;
                tides.push_back(t_rel);
            }
        }
    
        // 计算码头i的不可达区间(在[日出,日落]内)
        double w_i = inaccess[i] * 3600.0;
        vector<pair<double, double> > intervals;
        for (int idx = 0; idx < tides.size(); idx++) {
            double t_tide = tides[idx];
            double L = max(sunrise_d, t_tide - w_i);
            double R = min(sunset_d, t_tide + w_i);
            if (L <= R + eps) {
                intervals.push_back(make_pair(L, R));
            }
        }
    
        // 合并重叠的区间
        vector<pair<double, double> > merged;
        if (!intervals.empty()) {
            sort(intervals.begin(), intervals.end());
            double L = intervals[0].first, R = intervals[0].second;
            for (int idx = 1; idx < intervals.size(); idx++) {
                if (intervals[idx].first <= R + eps) {
                    R = max(R, intervals[idx].second);
                } else {
                    merged.push_back(make_pair(L, R));
                    L = intervals[idx].first;
                    R = intervals[idx].second;
                }
            }
            merged.push_back(make_pair(L, R));
        }
    
        // 计算最早出发时间
        double current = sunrise_d;
        double depart_time = -1;
        for (int idx = 0; idx < merged.size(); idx++) {
            double L = merged[idx].first, R = merged[idx].second;
            if (current + eps < L) {
                depart_time = current;
                break;
            } else {
                if (current < R + eps) {
                    current = R + eps;
                }
            }
        }
        if (depart_time < 0) {
            if (current < sunset_d + eps) {
                depart_time = current;
            } else {
                return false;
            }
        }
        if (depart_time > sunset_d + eps) {
            return false;
        }
    
        // 计算划行时间(秒)
        double time_paddle = (dists[j] - dists[i]) / speed * 3600.0;
        double t_arrive = depart_time + time_paddle;
        if (t_arrive > sunset_d + eps) {
            return false;
        }
    
        // 检查到达码头j时是否可达
        double w_j = inaccess[j] * 3600.0;
        for (int idx = 0; idx < tides.size(); idx++) {
            double t_tide = tides[idx];
            double low_start = t_tide - w_j;
            double low_end = t_tide + w_j;
            if (t_arrive >= low_start - eps && t_arrive <= low_end + eps) {
                return false;
            }
        }
    
        return true;
    }
    
    int main() {
        int max_days;
        while (cin >> max_days) {
            if (max_days == 0) break;
    
            double speed;
            cin >> speed;
    
            string sunrise_str, sunrise_interval_str;
            cin >> sunrise_str >> sunrise_interval_str;
            int sunrise0 = str_to_seconds(sunrise_str);
            int sunrise_interval = str_to_seconds(sunrise_interval_str);
    
            string sunset_str, sunset_interval_str;
            cin >> sunset_str >> sunset_interval_str;
            int sunset0 = str_to_seconds(sunset_str);
            int sunset_interval = str_to_seconds(sunset_interval_str);
    
            string tide_str, tide_interval_str;
            cin >> tide_str >> tide_interval_str;
            int tide0 = str_to_seconds(tide_str);
            int tide_interval = str_to_seconds(tide_interval_str);
    
            int n_docks;
            cin >> n_docks;
            int n = n_docks + 1; // 总点数(包括起点0和终点)
            vector<double> dists(n);
            vector<int> inaccess(n);
    
            for (int i = 0; i < n; i++) {
                cin >> dists[i] >> inaccess[i];
            }
    
            // 动态规划数组:dp[d][i]存储第d天到达码头i的路径序列
            vector<vector<vector<int> > > dp(max_days + 1, vector<vector<int> >(n));
            dp[0][0] = vector<int>(1, 0); // 第0天在起点0
    
            int min_days = -1;
            vector<int> final_path;
    
            for (int d = 1; d <= max_days; d++) {
                for (int i = 0; i < n; i++) {
                    if (dp[d - 1][i].empty()) continue;
    
                    // 尝试到达更远的码头j(从远到近尝试)
                    for (int j = n - 1; j > i; j--) {
                        if (check_feasible(d, i, j, dists, inaccess, speed, sunrise0, sunrise_interval,
                                          sunset0, sunset_interval, tide0, tide_interval)) {
                            vector<int> candidate = dp[d - 1][i];
                            candidate.push_back(j);
    
                            // 如果dp[d][j]为空或当前路径更优
                            if (dp[d][j].empty() || greater_path(candidate, dp[d][j])) {
                                dp[d][j] = candidate;
                            }
                        }
                    }
                }
    
                // 如果到达终点,记录最小天数
                if (!dp[d][n - 1].empty()) {
                    min_days = d;
                    final_path = dp[d][n - 1];
                    break;
                }
            }
    
            if (min_days == -1) {
                cout << "NO ITINERARY POSSIBLE" << endl;
            } else {
                // 输出从第1天到第min_days天的停靠码头
                for (int i = 1; i <= min_days; i++) {
                    if (i > 1) cout << " ";
                    cout << final_path[i];
                }
                cout << endl;
            }
        }
        return 0;
    }
    • 1

    信息

    ID
    588
    时间
    1000ms
    内存
    10MiB
    难度
    9
    标签
    递交数
    1
    已通过
    0
    上传者