P7913 [CSP-S 2021] 廊桥分配
暴力枚举
枚举国内和国外的廊桥数量配额,再模拟航班停机过程
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 100005;
struct Flight {
int l, r; // l 抵达时刻,r 离开时刻
bool operator<(const Flight& other) const {
return l < other.l;
}
};
Flight a[N], b[N]; // a 国内,b 国际
int t[N]; // 廊桥目前停靠飞机的离开时刻
int solve(Flight f[], int m, int len) {
for (int i = 1; i <= len; i++) t[i] = 0;
int cnt = 0;
for (int i = 1; i <= m; i++) {
int id = 0;
for (int j = 1; j <= len; j++)
if (f[i].l >= t[j]) {
id = j; break;
}
if (id != 0) {
t[id] = f[i].r; cnt++;
}
}
return cnt;
}
int main()
{
int n, m1, m2;
scanf("%d%d%d", &n, &m1, &m2);
for (int i = 1; i <= m1; i++) scanf("%d%d", &a[i].l, &a[i].r);
for (int i = 1; i <= m2; i++) scanf("%d%d", &b[i].l, &b[i].r);
// 按抵达时间排序
sort(a + 1, a + m1 + 1); sort(b + 1, b + m2 + 1);
int ans = 0;
for (int x = 0; x <= n; x++) {
// 给国内航班预留 x 个廊桥,国外航班预留 n-x 个
int y = n - x;
int cnt1 = solve(a, m1, x);
int cnt2 = solve(b, m2, y);
ans = max(ans, cnt1 + cnt2);
}
printf("%d\n", ans);
return 0;
}
正解
#include <cstdio>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 1e5 + 5;
struct Flight {
int arr;
int lv;
bool operator<(const Flight& other) const {
return arr < other.arr;
}
};
Flight f1[N], f2[N];
int bri[N]; // bri[i]记录第i个廊桥什么时候空闲
int bucket[N]; // bucket[i]记录廊桥充足时,第i个廊桥停过几次航班
int ans1[N], ans2[N]; // 国内/国际的bucket的前缀和
struct Compare {
bool operator()(int i, int j) {
return bri[i] > bri[j];
}
};
void process(Flight f[N], int n, int m) {
for (int i = 1; i <= n; i++) {
bri[i] = 0;
bucket[i] = 0;
}
priority_queue<int, vector<int>, greater<int>> free;
priority_queue<int, vector<int>, Compare> occ; // occupied
for (int i = 1; i <= n; i++) free.push(i);
for (int i = 1; i <= m; i++) {
// 根据f[i].arr这个抵达时间
// 把一部分被占用的廊桥释放掉
// 所有之前被占用的廊桥如果它对应的航班的起飞时间
// <= f[i].arr 应当变回空闲廊桥
// 这就意味着存放被占用廊桥的容器应当以“起飞时间”把廊桥释放出来
while (!occ.empty() && bri[occ.top()] <= f[i].arr) {
free.push(occ.top());
occ.pop();
}
// 你要找的是空闲廊桥中编号最小的那个
if (!free.empty()) {
int u = free.top(); free.pop();
bri[u] = f[i].lv;
bucket[u]++;
// 应当把这个空闲廊桥变成被占用状态
occ.push(u);
}
}
}
int main()
{
int n, m1, m2;
scanf("%d%d%d", &n, &m1, &m2);
for (int i = 1; i <= m1; i++) {
scanf("%d%d", &f1[i].arr, &f1[i].lv);
}
for (int i = 1; i <= m2; i++) {
scanf("%d%d", &f2[i].arr, &f2[i].lv);
}
sort(f1 + 1, f1 + m1 + 1);
sort(f2 + 1, f2 + m2 + 1);
// 枚举所有分配方案
process(f1, n, m1);
// 此时bucket[]是国内航班廊桥安排情况
for (int i = 1; i <= n; i++) {
ans1[i] = ans1[i-1] + bucket[i];
}
process(f2, n, m2);
for (int i = 1; i <= n; i++) {
ans2[i] = ans2[i-1] + bucket[i];
}
int ans = 0;
for (int i = 0; i <= n; i++) {
int j = n - i;
// 给国内i个廊桥,给国际j个廊桥
ans = max(ans, ans1[i] + ans2[j]);
}
printf("%d\n", ans);
return 0;
}

浙公网安备 33010602011771号