贪心:Stall Reservations S
题目:P2859 [USACO06FEB] Stall Reservations S - 洛谷
题目概述:每头奶牛都有自己的产奶时段(包括边界点),产奶时要单独呆在牛棚里。问至少需要多少牛棚?奶牛产奶时呆在哪个牛棚里?
思路:
怎么找?
找最早结束牛棚的那一个。如果奶牛的产奶时间,小于等于,最早结束牛棚产奶的那一头奶。说明需要新牛棚。
如果有多个牛棚怎么办?
都可以用,但我们这里用最早结束的牛棚。
有点点复杂~配代码分析:
#include <iostream>
#include <queue>
#include <algorithm>using namespace std;
const int N = 5e4 + 10;
int n;
struct node
{
int x; // 起始时间/结束时间
int y; // 终止时间/牛棚标号
int z; // 排序之前的编号
//比较器的工作
//如果返回 true,表示第一个参数比第二个参数“优先级低”,应该排在后面。
//如果返回 false,表示第一个参数比第二个参数“优先级高”,应该排在前面。
//std::priority_queue默认使用 std::less<T>作为比较器,而 std::less<T>内部调用的是 operator<
bool operator<(const node& a) const
{
return x > a.x; //使优先队列按x从小到大排序(小顶堆)
}}a[N];
int ret[N];
bool cmp(node&x , node& y)
{
return x.x < y.x; //按起始时间从小到大排序
}
int main()
{
cin >> n;
for (int i = 1; i <= n; i++)
{
cin >> a[i].x >> a[i].y;
a[i].z = i; //记录原始编号
}
sort(a+1, a+1+n, cmp); //按起始时间排序
int num = 1; //牛棚技术器
priority_queue<node> heap; //优先队列,存储(结束时间,牛棚编号)
//默认参数:等价于priority_queue<node, vector<node>, less<node>> heap;
//初始化
ret[a[1].z] = 1; //第一头奶牛分配牛棚1
heap.push({a[1].y, 1}); //将结束时间和牛棚编号加入队列
// {a[1].y, 1} 是一个初始化列表,用于构造一个 node对象
// 等价于
// node temp;
// temp.x = a[1].y;
// temp.y = 1;
// heap.push(temp);
for (int i = 2; i <= n; i++)
{
int l = a[i].x, r = a[i].y; //当前奶牛的起始时间和结束时间
if (l <= heap.top().x) // 如果当前起始时间小于等于 最早结束的牛棚的结束时间
{
num++; //需要新牛棚
ret[a[i].z] = num; //分配新编号
heap.push({r, num}); //新牛棚入队
}
else
{
node t = heap.top(); heap.pop(); //获取最早结束的牛棚
ret[a[i].z] = t.y; //分配该牛棚编号
heap.push({r, t.y}); //更新结束时间后重新入队
}
}
cout << num << endl;
for (int i = 1; i <= n; i++) cout << ret[i] << endl;
return 0;
}
总代码:
#include <iostream>
#include <queue>
#include <algorithm>using namespace std;const int N = 5e4 + 10;int n;
struct node
{int x; // 起始时间/结束时间 int y; // 终止时间/牛棚标号 int z; // 排序之前的编号 bool operator<(const node& a) const{return x > a.x; //使优先队列按x从小到大排序(小顶堆)}
}a[N];
int ret[N];bool cmp(node&x , node& y)
{return x.x < y.x; //按起始时间从小到大排序
}int main()
{cin >> n;for (int i = 1; i <= n; i++){cin >> a[i].x >> a[i].y;a[i].z = i; //记录原始编号 } sort(a+1, a+1+n, cmp); //按起始时间排序 int num = 1; //牛棚技术器 priority_queue<node> heap; //优先队列,存储(结束时间,牛棚编号)//初始化 ret[a[1].z] = 1; //第一头奶牛分配牛棚1 heap.push({a[1].y, 1}); //将结束时间和牛棚编号加入队列 for (int i = 2; i <= n; i++){int l = a[i].x, r = a[i].y; //当前奶牛的起始时间和结束时间 if (l <= heap.top().x) // 如果当前起始时间小于等于最早结束的牛棚的结束时间{num++; //需要新牛棚 ret[a[i].z] = num; //分配新编号 heap.push({r, num}); //新牛棚入队 }else{node t = heap.top(); heap.pop(); //获取最早结束的牛棚 ret[a[i].z] = t.y; //分配该牛棚编号 heap.push({r, t.y}); //更新结束时间后重新入队 }}cout << num << endl;for (int i = 1; i <= n; i++) cout << ret[i] << endl;return 0;}
时间复杂度分析:
-
输入读取:循环读取 n 头奶牛的数据,时间复杂度为 O(n)。
-
排序:使用
sort
函数对奶牛按起始时间从小到大排序,时间复杂度为 O(n log n)。 -
优先队列操作:
-
初始化:将第一头奶牛的信息加入优先队列,操作时间为 O(1)。
-
循环处理剩余 n-1 头奶牛:每次循环中,访问堆顶元素(O(1)时间),并可能执行堆的弹出(pop)和插入(push)操作。堆操作(pop 和 push)的时间复杂度为 O(log k),其中 k 是堆的大小(最大为 n)。因此,处理所有奶牛的总时间复杂度为 O(n log n)。
-
总时间复杂度:
-
主导项是排序和优先队列操作,两者都是 O(n log n),因此总时间复杂度为 O(n log n)。