ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[CSP-S 2021] 廊桥分配 题解

2021-10-31 11:00:29  阅读:400  来源: 互联网

标签:int 题解 top pop id push 廊桥 CSP


写篇题解来纪念我炸掉的CSP

唯一会做的题代码写挂了(痛苦面具

思路

我看到这道题第一眼想到的是线段树,感觉可以用线段树维护飞机入站到出战的这段时间,想了半天想不到代码怎么写

国内机场与国外机场要分开计算

突然发现可以用一个优先队列来维护飞机出站的时间,给每架飞机按入站时间排好序后可以从小到大依次让飞机入站,并比较此时是否有飞机出站,有就把队首元素弹出。

40 pts

可以暴力枚举每一种国内机场和国际机场廊桥的分配方案。

代码如下:

#include <bits/stdc++.h>
#include <functional>
#define N 100010
using namespace std;

struct node {
	int a, b;
} fa[N], fc[N];//分别为国外机场航班和国内机场航班
int n, m1, m2, _ans;

bool cmp(node a, node b) {
	return a.a < b.a;
}

void check(int ans) {//ans表示国内机场分配的廊桥数
	priority_queue <int, vector<int>, greater<int> > q;
	int res = 0;
	for (int i = 1; i <= m1; i++) {
		int s = fc[i].a;
		while (!q.empty() && s > q.top()) {
			q.pop();//弹出已经出站的飞机
		}
		if (q.size() < ans) {
			q.push(fc[i].b);//如果有空余的廊桥就加入廊桥
			res++;//答案+1
		}
	}

	while (!q.empty())
		q.pop();//清空队列元素

	for (int i = 1; i <= m2; i++) {
		int s = fa[i].a;
		while (!q.empty() && s > q.top()) {
			q.pop();
		}
		if (q.size() < n - ans) {//n-ans表示国外机场分配的廊桥数
			q.push(fa[i].b);//同上
			res++;
		}
	}
	_ans = max(_ans, res);
	return ;
}

int main() {
	scanf("%d%d%d", &n, &m1, &m2);
	for (int i = 1; i <= m1; i++) {
		scanf("%d%d", &fc[i].a, &fc[i].b);
	}
	for (int i = 1; i <= m2; i++) {
		scanf("%d%d", &fa[i].a, &fa[i].b);
	}
	sort(fc + 1, fc + 1 + m1, cmp);
	sort(fa + 1, fa + 1 + m2, cmp);//按入站时间排序

	for (int i = 0; i <= n; i++) {
		check(i);//暴力枚举统计答案
	}

	printf("%d", _ans);
	return 0;
}

复杂度为O(nm logm)

100pts

以上做法的复杂度太高,这时候想有没有什么办法可以一遍就统计出所有分配方案的答案,然后统计答案。

统计答案的代码:

for (int i = 0; i <= n; i++) {
	if (ans1[i] + ans2[n - i] > maxn) {
		maxn = ans1[i] + ans2[n - i];
	}
}

如果给每个廊桥都编上号,每次飞机入站都选择空闲的廊桥中编号最小的哪一个。

这样可以排除分配方案的影响。

用一个优先队列来维护廊桥编号,一开始将所有廊桥入队。

对于每一架飞机可以用一个pair分别存储飞机出站的时间以及停靠的廊桥的编号。

用优先队列来维护pair

每次飞机入站时先比较有没有应该出站的飞机,如果有就把他们从队列中弹出,并把对应的廊桥编号再加入优先队列中。

然后飞机选择编号最小的廊桥停靠。并把对应的廊桥的ans加一。

这样就能快速的统计出每个廊桥产生的贡献,再把所有编号比它小的廊桥产生的贡献加起来,用前缀和数组来维护。

最后用上面的代码统计一遍答案就好了。

代码如下

void check() {
	priority_queue<int, vector<int>, greater<int> > q;//维护廊桥编号
	priority_queue<P, vector<P>, greater<P> > p;//维护飞机出站时间和停靠的廊桥的编号
	for (int i = 1; i <= n; i++) {
		q.push(i);//一开始所有廊桥都处于空闲状态,把所有廊桥加入队列。
	}
	for (int i = 1; i <= m1; i++) {
		int s = fc[i].a;//该架飞机入站时间
		while (!p.empty() && s > p.top().first) {
			//弹出已经飞走的飞机并把它所停课的廊桥加入队列
			q.push(p.top().second);
			p.pop();
		}
		if (!q.empty()) {
			int id = q.top();
			q.pop();//取编号最小的廊桥停靠
			ans1[id]++;//该编号的廊桥产生的贡献加一
			p.push(P(fc[i].b, id));
		}
	}
	while (!q.empty())
		q.pop();
	while (!p.empty())
		p.pop();
	//清空队列
	for (int i = 1; i <= n; i++) {
		q.push(i);
	}
	//同上
	for (int i = 1; i <= m2; i++) {
		int s = fa[i].a;
		while (!p.empty() && s > p.top().first) {
			q.push(p.top().second);
			p.pop();
		}
		if (!q.empty()) {
			int id = q.top();
			q.pop();
			ans2[id]++;
			p.push(P(fa[i].b, id));
		}
	}
	for (int i = 1; i <= n; i++) {
		ans1[i] += ans1[i - 1];
		ans2[i] += ans2[i - 1];
	}
	//前缀和数组维护每种分配方案产生的答案
	return;
}

复杂度 O(nlogn)

Code

#include <bits/stdc++.h>
#include <cstdio>
#include <functional>
#define P pair <int,int>
using namespace std;

struct node {
	int a, b;
} fc[100010], fa[100010];

bool cmp(node a, node b) {
	return a.a < b.a;
}
int n, m1, m2, maxn = -1, ans1[100010], ans2[100010];

void check() {
	priority_queue<int, vector<int>, greater<int> > q;//维护廊桥编号
	priority_queue<P, vector<P>, greater<P> > p;//维护飞机出站时间和停靠的廊桥的编号
	for (int i = 1; i <= n; i++) {
		q.push(i);//一开始所有廊桥都处于空闲状态,把所有廊桥加入队列。
	}
	for (int i = 1; i <= m1; i++) {
		int s = fc[i].a;//该架飞机入站时间
		while (!p.empty() && s > p.top().first) {
			//弹出已经飞走的飞机并把它所停课的廊桥加入队列
			q.push(p.top().second);
			p.pop();
		}
		if (!q.empty()) {
			int id = q.top();
			q.pop();//取编号最小的廊桥停靠
			ans1[id]++;//该编号的廊桥产生的贡献加一
			p.push(P(fc[i].b, id));
		}
	}
	while (!q.empty())
		q.pop();
	while (!p.empty())
		p.pop();
	//清空队列
	for (int i = 1; i <= n; i++) {
		q.push(i);
	}
	//同上
	for (int i = 1; i <= m2; i++) {
		int s = fa[i].a;
		while (!p.empty() && s > p.top().first) {
			q.push(p.top().second);
			p.pop();
		}
		if (!q.empty()) {
			int id = q.top();
			q.pop();
			ans2[id]++;
			p.push(P(fa[i].b, id));
		}
	}
	for (int i = 1; i <= n; i++) {
		ans1[i] += ans1[i - 1];
		ans2[i] += ans2[i - 1];
	}
	//前缀和数组维护每种分配方案产生的答案
	return;
}

int main() {
	scanf("%d%d%d", &n, &m1, &m2);
	for (int i = 1; i <= m1; i++) {
		scanf("%d%d", &fc[i].a, &fc[i].b);
	}
	for (int i = 1; i <= m2; i++) {
		scanf("%d%d", &fa[i].a, &fa[i].b);
	}
	sort(fc + 1, fc + 1 + m1, cmp);
	sort(fa + 1, fa + 1 + m2, cmp);
	check();
	//统计答案
	for (int i = 0; i <= n; i++) {
		if (ans1[i] + ans2[n - i] > maxn) {
			maxn = ans1[i] + ans2[n - i];
		}
	}
	printf("%d", maxn);
	return 0;
}

标签:int,题解,top,pop,id,push,廊桥,CSP
来源: https://www.cnblogs.com/Dregen-Yor/p/15488704.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有