前言
POJ题解这一系列文章主要记录《挑战程序设计程序设计》的课后习题,包括解题需要用到的知识,思路以及遇到的问题等等。提示:以下是本篇文章正文内容,下面案例可供参考
一、题目大意
农夫约翰正分配他的
N
N
N头(1
⩽
\leqslant
⩽
N
N
N
⩽
\leqslant
⩽ 25,000)牛在谷仓周围做一些清洁工作。 约翰将一天分为
T
T
T个班次(1
⩽
\leqslant
⩽
T
T
T
⩽
\leqslant
⩽ 1,000,000),第一个是班次1,最后一个是班次T。
每头牛仅在一天中的某个时间间隔可用以进行清洁工作。 任何被选定负责清洁工作的母牛将在整个间隔时间内工作。
你的工作是帮助农夫约翰分配一些奶牛到班次,以便
(i)每个班次至少分配一头奶牛。
(ii)尽可能少地牛参与清洁工作。 如果无法为每个班次分配一头牛,请 打印-1。
1.输入
行数 | 输入1 | 输入2 |
---|---|---|
第1行 | 牛的数量N | 班次T |
第2~N+1行 | 每头牛的起始班次 | 每头牛的结束班次 |
2.输出
最少需要分配的牛的头数(如果无法为每个班次分配一头牛,打印-1)
二、解题思路
贪心算法
- 我们用一个pair结构对每头牛的开始班次和结束班次进行存储,然后对每头牛的工作时间按起始时间升序,结束时间降序(起始时间相等时)的规则进行排序。
- 依次考虑每一头牛。首先考虑第一头牛,如果第一头牛的起始时间大于1(即没有牛能排到第一班),打印-1。
- 选取第n头牛时,需要使第 n n n头牛的起始时间 ⩽ \leqslant ⩽第 n − 1 n-1 n−1头牛的结束时间,第 n n n头牛的结束时间大于第 n − 1 n-1 n−1头牛的结束时间。同时第 n n n头牛的结束时间应该尽可能大。如果第n头牛的起始时间大于 第 第 第n-1$头牛的结束时间+1,打印-1。
思考
为什么需要使第
n
n
n头牛的起始时间
⩽
\leqslant
⩽第
n
−
1
n-1
n−1头牛的结束时间+1,而不是第
n
n
n头牛的起始时间
⩽
\leqslant
⩽第
n
−
1
n-1
n−1头牛的结束时间?
考虑以下测试数据:
行数 | 输入1 | 输入2 |
---|---|---|
第1行 | 4 | 10 |
第2行 | 1 | 6 |
第3行 | 2 | 7 |
第4行 | 3 | 6 |
第5行 | 8 | 10 |
输出结果为3,而不是-1。因为可以选取1-6,2-7,8-10。所以需要使第 n n n头牛的起始时间 ⩽ \leqslant ⩽第 n − 1 n-1 n−1头牛的结束时间+1
三、AC代码
#include<iostream>
#include<algorithm>
using namespace std;
#define MAX_N 25010
typedef pair<int,int> P;//使用pair来存储每头牛的起始班次和结束班次
P p[MAX_N];
int N,T;//N为牛的头数,T为班次数
bool cmp(P p1,P p2){
//此处的cmp应用于sort方法,使牛按起始班次升序排序,当起始班次相等时,按结束班次降序排序
if(p1.first!=p2.first) return p1.first<p2.first;
else
return p1.second>=p2.second;
}
int solve(){
if(p[0].first>1)//当第一头牛的起始时间大于1,则班次1无法安排任何一头牛,返回-1
return -1;
int res =1;//最少需要分配的牛的头数
int index =p[0].second;//index用于存储前n-1头牛可以排到的最后班次
int end =p[0].second;//end用于存储正在选取的牛可以排到的最后班次
int i=1;
bool change; //是否有选到新的牛
while(i<N){//考虑N头牛
if(end>=T) return res;//当end>=T时,返回res
if(p[i].first>end+1||N<1){
/*当后面的牛的起始时间比n-1头牛可以排到的最后班次时间大1以上时,返回-1
例如 3 8
1 3
5 6
7 8
输出-1,5比3大2 */
return -1;
}
change = false;
while(i<N&&p[i].first<=index+1){
//printf("line 25 i =%d\n",i);
if(p[i].second>index&&p[i].second>end){
end =p[i].second;//实时更新end
change =true;
}
//printf("line 27 end =%d\n",end);
i++;
}
if(change){
res++;//当有选取新的牛时,res++
index =end;//更新index
}
}
if(end>=T){
return res;//当end>=T时,返回res,否则返回-1
}
else{
return -1;
}
}
int main(){
while(scanf("%d %d",&N,&T)==2){//因为需要多组输入,所以需要使用while(scanf)
for(int i=0;i<N;i++){
scanf("%d %d",&p[i].first,&p[i].second);
}
sort(p,p+N,cmp);//按第一位升序排序排序,如果第一位 相等,则按第二位降序排序
printf("%d\n",solve());
}
return 0;
}