当前位置:首页 > 提高组 > 2021年CSP-S廊桥分配问题解析(洛谷P7913):基于贪心算法与优先级队列的解题思路

2021年CSP-S廊桥分配问题解析(洛谷P7913):基于贪心算法与优先级队列的解题思路

9小时前

2021年CSP-S廊桥分配问题解析(洛谷P7913):基于贪心算法与优先级队列的解题思路 贪心算法 前缀和 第1张

一、题目解读

2021年CSP-S中的“廊桥分配”(洛谷P7913)是一个经典的资源分配问题。题目要求处理n个航班,每个航班有到达和离开时间,需在m1到m2个廊桥的限制下,计算使用不同数量的廊桥时能服务的最大航班数。核心在于高效分配廊桥资源,避免时间冲突,同时满足数量限制。

二、解题思路

采用贪心策略与优先级队列优化

1. 航班排序:按到达时间升序排列,确保处理顺序符合时间逻辑。

2. 动态分配:使用两个优先队列——available存储当前可用廊桥的释放时间,in_use存储正在使用的廊桥及释放时间。

3. 分配逻辑:

    优先使用已释放的廊桥(时间不冲突时);

    若无可用廊桥且剩余廊桥数未满,新建分配。

4. 前缀和优化:计算各廊桥数量的前缀和,便于快速查询不同k值下的最大服务数。

三、解题步骤

1. 输入与预处理:读取航班数据,按到达时间排序。

2. 初始化队列:available为空,in_use记录当前分配状态。

3. 循环分配:

    释放过期廊桥(到达时间前已完成的航班);

    若available不空,分配最小释放时间的廊桥;

    否则若廊桥数未满,新建分配。

4. 前缀和计算:累加各廊桥服务数,生成最终结果。

四、代码与注释

#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>
using namespace std;

// 计算使用k个廊桥时能服务的最大航班数
vector<int> calculate_max_flights(const vector<pair<int, int>>& flights, int max_bridges) {
    vector<int> res(max_bridges + 1, 0);
    if (flights.empty()) return res;
    
    // 按到达时间排序航班
    vector<pair<int, int>> sorted_flights = flights;
    sort(sorted_flights.begin(), sorted_flights.end());
    
    // 优先队列存储可用廊桥的释放时间
    priority_queue<int, vector<int>, greater<int>> available;
    // 优先队列存储正在使用的廊桥的释放时间
    priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> in_use;
    
    int count = 0;
    for (const auto& flight : sorted_flights) {
        int arrive = flight.first;
        int depart = flight.second;
        
        // 释放已经完成的廊桥
        while (!in_use.empty() && in_use.top().first <= arrive) {
            available.push(in_use.top().second);
            in_use.pop();
        }
        
        // 如果有可用廊桥,则分配
        if (!available.empty()) {
            int bridge = available.top();
            available.pop();
            in_use.push({depart, bridge});
            count++;
            if (bridge <= max_bridges) {
                res[bridge]++;
            }
        }
        // 如果没有可用廊桥但还有未分配的廊桥,则分配新的
        else if (in_use.size() < max_bridges) {
            int bridge = in_use.size() + 1;
            in_use.push({depart, bridge});
            count++;
            if (bridge <= max_bridges) {
                res[bridge]++;
            }
        }
    }
    
    // 计算前缀和
    for (int i = 1; i <= max_bridges; ++i) {
        res[i] += res[i - 1];
    }
    
    return res;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int n, m1, m2;
    cin >> n >> m1 >> m2;
    
    vector<pair<int, int>> domestic_flights(n);
    for (int i = 0; i < n; ++i) {
        cin >> domestic_flights[i].first >> domestic_flights[i].second;
    }
    vector<int> max_flights = calculate_max_flights(domestic_flights, m2);
    
    for (int i = m1; i <= m2; ++i) {
        cout << max_flights[i] << ';
    }
    cout << endl;
    
    return 0;
}


五、总结

算法通过优先级队列高效管理廊桥状态,结合贪心思想优先分配可用资源,避免回溯。前缀和的应用进一步简化了结果查询过程。时间复杂度为O(nlogn),适合处理大规模数据。关键点在于对资源释放时间的动态维护与分配优先级判断。


原创内容 转载请注明出处

分享给朋友:

相关文章

牛客13271题「删除K个数字的最小数」解题报告:贪心算法与栈的应用(附代码注释)

牛客13271题「删除K个数字的最小数」解题报告:贪心算法与栈的应用(附代码注释)

一、题目解读牛客13271题要求从给定的数字字符串中删除K个数字,使得剩余数字按原顺序排列后得到的最小数。题目核心在于如何在保持数字相对顺序的前提下,通过删除操作得到最优解。需注意结果字符串可能包含前...

洛谷P2190题解:铁路售票系统车厢计算(差分数组+前缀和优化)

洛谷P2190题解:铁路售票系统车厢计算(差分数组+前缀和优化)

一、题目解读洛谷P2190题要求解决铁路售票系统中的车厢数量计算问题。题目给定n个车站和m条订票申请,每条申请包含区间[x,y)及乘客数z。需要计算在不超载的情况下(每节车厢最多36人),满足所有乘客...

洛谷P1121题解:动态规划求解环形数组最大子段和问题(附代码注释)

洛谷P1121题解:动态规划求解环形数组最大子段和问题(附代码注释)

一、题目解读洛谷P1121题要求求解环形数组的最大子段和,即在一个环形数组中找到一个连续子段,使其元素和最大。环形数组的特殊性在于首尾元素可相连,需考虑线性子段与跨越首尾的环形子段两种情况。二、解题思...

洛谷P12597题解:子序列查找的贪心与二分优化详解

洛谷P12597题解:子序列查找的贪心与二分优化详解

一、题目解读洛谷P12597题目要求在一个字符串s中寻找最长的子序列,该子序列需满足字符顺序与另一个字符串t相同。题目强调子序列无需连续,但字符相对位置需保持一致。例如,若t为"abc&qu...

力扣LCR074题区间合并算法解析:贪心排序与区间重叠处理

力扣LCR074题区间合并算法解析:贪心排序与区间重叠处理

一、题目解读力扣LCR074题要求对给定的二维区间数组(每个区间由起始点和终止点构成)进行合并,将重叠的区间合并为更宽的区间,最终输出不重叠的合并结果。例如,输入[[1,3],[2,6],[8,10]...

牛客4577题解:滑动窗口解法

牛客4577题解:滑动窗口解法

一、题目解读牛客4577题要求处理多组测试数据,每组包含一个整数数组crimes和两个参数n(数组长度)、t(阈值)、c(窗口大小)。题目需要统计数组中所有长度恰好为c的子数组,其元素和不超过t的数量...

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。