2021_CSP-S_T2_廊桥分配题解

参考处-依此补充了一些内容       原题1-洛谷P7913        原题2-一本通T2078

这道题数据范围达到了10^5,用暴力破解指定不行,但我们可以仿照思路,进行修改优化。我们先不管廊桥数量,维护两个优先队列,每一个飞机到达,我们就给他最小的廊桥进行分配。加上廊桥数,跟刚才同理,如果超过了n个廊桥,那么我们就把第n+1个廊桥看作远机位,代码实现直接continue即可。

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

// 定义pair<int, int>的别名,用于存储离开时间和廊桥编号
typedef pair<int, int> pii;

// 定义航班结构体,存储航班的到达时间和离开时间
struct range {
  int x, y; // x: 到达时间,y: 离开时间
} a[100005], b[100005]; // a: 国内航班,b: 国际航班

// res1: 国内航班使用i个廊桥时能停靠的飞机数量
// res2: 国际航班使用i个廊桥时能停靠的飞机数量
int res1[100005], res2[100005];
int n; // 廊桥总数

// 比较函数,用于按照到达时间排序
bool cmp(const range& a, const range& b){ 
    return a.x < b.x; // 按到达时间升序排列
}

// 计算函数:计算在给定航班数据下,使用不同数量廊桥能停靠的飞机数量
// t: 航班数组,m: 航班数量,res: 结果数组
void calc(range* t, int m, int* res){
  // lq: 最小堆,存储正在使用的廊桥的离开时间和廊桥编号
  // 堆顶是离开时间最早的廊桥
  priority_queue<pii, vector<pii>, greater<pii> > lq;
  
  // wq: 最小堆,存储当前空闲的廊桥编号
  priority_queue<int, vector<int>, greater<int> > wq;
  
  // 初始化所有廊桥为空闲状态
  for (int i = 1; i <= n; i++) wq.push(i);
  
  // 处理每个航班
  for (int i = 1; i <= m; i++) {
    // 检查是否有航班已经离开,释放廊桥
    // 如果当前航班的到达时间 >= 堆顶航班的离开时间,说明该廊桥已空闲
    while (!lq.empty() && t[i].x >= lq.top().first) {
      wq.push(lq.top().second); // 将廊桥编号加入空闲队列
      lq.pop(); // 弹出已离开的航班
    }
    
    // 如果没有空闲廊桥,跳过当前航班
    if (wq.empty()) continue;
    
    // 分配廊桥:取编号最小的空闲廊桥
    int dest = wq.top();
    wq.pop();
    
    // 记录该廊桥停靠的飞机数量+1
    res[dest]++;
    
    // 将当前航班加入使用中的廊桥队列,记录离开时间和使用的廊桥编号
    lq.push(make_pair(t[i].y, dest));
  }
  
  // 计算前缀和:res[i]表示使用i个廊桥时能停靠的飞机总数
  for (int i = 1; i <= n; i++) res[i] += res[i - 1];
}

int main(){
    int m1, m2; // m1: 国内航班数量,m2: 国际航班数量
    cin >> n >> m1 >> m2;
    
    // 读取国内航班数据
    for (int i = 1; i <= m1; i++) cin >> a[i].x >> a[i].y;
    // 读取国际航班数据
    for (int i = 1; i <= m2; i++) cin >> b[i].x >> b[i].y;
    
    // 按到达时间排序航班
    sort(a + 1, a + m1 + 1, cmp);
    sort(b + 1, b + m2 + 1, cmp);
    
    // 计算国内和国际航班的结果
    calc(a, m1, res1);
    calc(b, m2, res2);
    
    // 寻找最优分配方案:国内使用i个,国际使用n-i个
    int ans = 0;
    for (int i = 0; i <= n; i++) 
        ans = max(ans, res1[i] + res2[n - i]);
    
    // 输出结果
    cout << ans << endl;
    return 0;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值