POJ 2376 Cleaning Shifts


前言

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

二、解题思路

贪心算法

  1. 我们用一个pair结构对每头牛的开始班次和结束班次进行存储,然后对每头牛的工作时间按起始时间升序,结束时间降序(起始时间相等时)的规则进行排序。
  2. 依次考虑每一头牛。首先考虑第一头牛,如果第一头牛的起始时间大于1(即没有牛能排到第一班),打印-1。
  3. 选取第n头牛时,需要使第 n n n头牛的起始时间 ⩽ \leqslant n − 1 n-1 n1头牛的结束时间,第 n n n头牛的结束时间大于第 n − 1 n-1 n1头牛的结束时间。同时第 n n n头牛的结束时间应该尽可能大。如果第n头牛的起始时间大于 第 第 n-1$头牛的结束时间+1,打印-1。

思考

为什么需要使第 n n n头牛的起始时间 ⩽ \leqslant n − 1 n-1 n1头牛的结束时间+1,而不是第 n n n头牛的起始时间 ⩽ \leqslant n − 1 n-1 n1头牛的结束时间?
考虑以下测试数据:

行数输入1输入2
第1行410
第2行16
第3行27
第4行36
第5行810

输出结果为3,而不是-1。因为可以选取1-6,2-7,8-10。所以需要使第 n n n头牛的起始时间 ⩽ \leqslant n − 1 n-1 n1头牛的结束时间+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;
}


总结

以上就是今天要讲的内容,本文使用了贪心算法对POJ2376进行了题解,这道题思考难度不大,但是需要考虑到多种特殊的情况,不然特别容易Wrong Answer.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值