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;
}
posted @ 2023-09-26 18:04  RonChen  阅读(192)  评论(0)    收藏  举报