学习记录 poj3190 畜栏分配(贪心算法)
题目描述
vjudge链接
大意:已知有
N
(
1
≤
N
≤
50
,
000
)
N (1\le N\le 50,000)
N(1≤N≤50,000)头奶牛需要在畜栏中挤奶,现给出奶牛总数
N
N
N及每头奶牛占用畜栏的开始时间
A
A
A、结束时间
B
(
1
≤
A
≤
B
≤
1
,
000
,
000
)
B(1\le A\le B\le 1,000,000)
B(1≤A≤B≤1,000,000), 且每个畜栏只能同时供一头奶牛使用,同一个畜栏的使用结束时间和下一次开始使用的时间不重合。求至少建立多少个畜栏才能满足需要,及每头奶牛使用的畜栏编号。
样例输入
第一行输入奶牛的数目$N$,其后每行给出各头奶牛挤奶的开始时间$A$、结束时间$B$,二者用空格隔开。
5
1 10
2 4
3 6
5 8
4 7
输出
第一行输出最少需要的畜栏数目,其后各行输出各头奶牛使用的畜栏编号。
例:第2行输出1表明第一头奶牛
(
A
1
=
1
,
B
1
=
10
)
(A_1 = 1, B_1 = 10)
(A1=1,B1=10)使用1号(第1个建立的)畜栏。
4
1
2
3
2
4
解题思路
贪心算法
每次开始挤奶只考虑当前情况下的最优解。
对每头奶牛按开始挤奶的时间升序排列(先开始挤奶的排在前面),每个畜栏按结束时用的时间生升序排列(先使用完的排在前面),每次一头奶牛开始挤奶,检验当前最早结束使用的畜栏是否空闲,尽可能充分利用已有畜栏达到最少建立畜栏的目的。
代码
#include <iostream>
#include <algorithm> //调用sort函数
#include <queue> //调用优先队列
#include <cstring> //调用memset()给数组置0
using namespace std;
struct Cow
{
int b, e; //开始时间b,结束时间e
int No; //奶牛编号
Cow(): b(1),e(1) { }
void Set(int bi, int en, int no)
{
b = bi;
e = en;
No = no;
}
//重载 ‘<’ 用于sort函数排序
bool operator<(const Cow & c) const
{
return b < c.b;
}
~Cow() { }
};
struct Stall
{
int end; //该畜栏使用结束时间
int No; //该畜栏编号
Stall(int e, int n): end(e), No(n) { }
//重载 ‘<’ 用于优先队列排序
bool operator < (const Stall & s) const
{
return end > s.end;
}
~Stall() { }
};
const int MAXN = 50050;
int pos[MAXN];
Cow cows[MAXN];
int main()
{
int n;
cin >> n;
// 数组在main函数中用变量n申请时vjudge编译不通过
// int pos[n];
// memset(pos, 0, sizeof(pos));
// Cow cows[n];
int bi, en;
for (int i = 0; i < n; i++)
{
cin >> bi >> en;
cows[i].Set(bi, en, i);
}
sort(cows, cows+n);
// //排序检验
// for (int i = 0; i < n; i++)
// {
// cout << cows[i].b << " ";
// }
// cout << endl;
int total = 0; //当前已修建畜栏总数
priority_queue<Stall, vector<Stall> > pq;
for (int i = 0; i < n; i++)
{
//第一头奶牛开始记奶时新建畜栏
if (total == 0)
{
total++;
Stall ss(cows[i].e, total);
pq.push(ss);
pos[cows[i].No] = total;
}
else
{
Stall st = pq.top(); //当前最早结束使用的畜栏
//注意'<',两头奶牛使用同一个畜栏时端点不能重合
if (st.end < cows[i].b )//有空闲畜栏可用
{
pq.pop();
pos[cows[i].No] = st.No; //编号为cows[i].No的奶牛使用编号st.No的畜栏
Stall ss(cows[i].e, st.No);
pq.push(ss);
}
else //无空闲畜栏可用,新建畜栏
{
total++;
Stall(cows[i].e, total);
pq.push(ss);
pos[cows[i].No] = total;
}
}
// //分配检验
// for(int j = 0; j < n; j++)
// {
// cout << pos[j] << " ";
// }
// cout << total << endl;
}
cout << total << endl;
for (int i = 0; i < n; i++)
{
cout << pos[i] << endl;
}
return 0;
}
关于sort排序函数和优先队列
sort(pfirst, pend, cmp);
//pfirst 指向排序数组的首地址
//pend 指向排序区间末尾的后一位
//cmp 比较函数
priority_queue<int, vector<int>, less<int> > q;
关于其中比较函数的个人看法:
cmp也可以看作“优先级”比较函数,不写比较函数时,sort默认从小到大排列,实际上cmp函数返回true时优先级高,故排在前面。相对的,优先队列中默认从大到小排列,比较函数返回true优先级低,排在后面。
详见大佬的帖子
优先队列
版权声明:本文为CSDN博主「C20182030Epic」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/c20182030/article/details/70757660