POJ 3927 Priest John's Busiest Day

题目大意:

        今天是神父John最忙的一天,镇里有N(1 ≤ N ≤ 100,000)对新婚夫妇要举办婚礼,每场婚礼都需要牧师当场为两位新人祝福祈祷,每对新人都计划好了各自婚礼的开始时间Si和结束时间Ti(Si、Ti都为int型自然整数),当地有一个习俗,那就是牧师祝福的时间必须超过整个婚礼时间的一半,并且:

        1. 牧师不能同时为两场婚礼祝福;

        2. 牧师到场和离开的时间都是整数;

        3. 牧师在结束一场祝福的瞬间就能到下一场进行祝福;

        求一个牧师祝福的合理顺序,使得所有新人的婚礼都能被牧师完整地祝福。

        现有多个测例,每个测例中都给出N,以及N长婚礼的Si和Ti,现要求你对每个测例进行判断,计算牧师能否将所有婚礼的完整祝福一遍,如果能输出YES,否则输出NO,每个测例占一行,输入以N = 0结束。

题目链接

注释代码:

/*                                             
 * Problem ID : POJ 3927 Priest John's Busiest Day  
 * Author     : Lirx.t.Una                                             
 * Language   : C++                            
 * Run Time   : 344 ms                                             
 * Run Memory : 1692 KB                                             
*/

#include <algorithm>
#include <iostream>
#include <cstdio>

//maximum number of couples
//婚礼的最大数量(最多有多少对夫妇)
#define	MAXCPN		100000

using namespace std;

struct	Wed {//wedding,婚礼
	
	int		s, t;//start,terminal,开始时间和结束时间
	int		as, at;//appear start and terminal,牧师必须出场的时间段
	
	void
	init(void) {
		
		scanf("%d%d", &s, &t);
		
		//牧师祝福时间必须超过婚礼时间的一半
		//因此可以由此计算出牧师最早结束祝福的时间at
		//和牧师最早的出场时间as
		//则[as, at]为牧师无论如何都得出场的时间
		if ( ( t - s ) % 2 ) {//奇数情况
			
			as = s + ( ( t - s - 1 ) >> 1 );
			at = as + 1;
		}
		else {//偶数情况
			
			as = s + ( ( t - s ) >> 1 ) - 1;
			at = as + 2;
		}
	}
	
	int
	mintv(void) {//minimum interval time
		//牧师至少祝福多长时间
		//即婚礼时间一半+1
		//用于贪心选择
		
		return ( t - s + 2 ) >> 1;
	}
	
	bool
	operator<(const Wed &oth)//将婚礼按照牧师最晚出席时间从小到大排序
	const {//如果有相等的情况则再按照最早离开时间从小到大排序,用于贪心选择
		
		return as < oth.as || ( as == oth.as && at < oth.at );
	}
};

Wed		w[MAXCPN];//wedding,婚礼

bool
can_hold_all(int n) {//判断牧师是否能正常祝福完所有新婚夫妇
	//即贪心选择的核心算法,在这之前必须先对婚礼进行sort排序
	
	int		cur_s, cur_t;//当前婚礼牧师的出场时间和牧师的离开时间
	int		prv_t;//上一场婚礼牧师的离开时间
	
	int		i;
	
	prv_t = (*w).mintv();//将prv_t初始化为第一场婚礼(下标为0)的最早结束时间
	//也就是说一切都进行地越早越好,可以方便为后续的祝福腾出更多时间
	//这就是贪心算法的核心!!!
	for ( i = 1; i < n; i++ ) {//从1开始往后检测
		
		cur_s = w[i].s;
		if ( cur_s < prv_t ) cur_s = prv_t;//如果当前婚礼开始时牧师上一场还没结束
		//则必须等牧师上一场结束后才能开始当前婚礼的祝福
		
		cur_t = cur_s + w[i].mintv();//让牧师尽早结束当前婚礼的祝福
		if ( cur_t > w[i].t ) return false;//如果当前婚礼祝福完时已经超出夫妻预设的结束时间
		//则牧师不能完成当前婚礼的祝福,所以失败退出
		
		prv_t = cur_t;//否则就是合理结束了,更新prv_v即可
	}
	
	return true;//一切正常,成功退出
}

int
main() {
	
	int		n;//婚礼数
	int		i;//计数变量
	
	while ( scanf("%d", &n), n ) {
		
		for ( i = 0; i < n; i++ ) w[i].init();
		sort(w, w + n);
		
		if ( can_hold_all(n) ) puts("YES");
		else puts("NO");
	}
	
	return 0;
}

无注释代码:

#include <algorithm>
#include <iostream>
#include <cstdio>

#define	MAXCPN		100000

using namespace std;

struct	Wed {
	
	int		s, t;
	int		as, at;
	
	void
	init(void) {
		
		scanf("%d%d", &s, &t);
		
		if ( ( t - s ) % 2 ) {
			
			as = s + ( ( t - s - 1 ) >> 1 );
			at = as + 1;
		}
		else {
			
			as = s + ( ( t - s ) >> 1 ) - 1;
			at = as + 2;
		}
	}
	
	int
	mintv(void) {
		
		return ( t - s + 2 ) >> 1;
	}
	
	bool
	operator<(const Wed &oth) 
	const {
		
		return as < oth.as || ( as == oth.as && at < oth.at );
	}
};

Wed		w[MAXCPN];

bool
can_hold_all(int n) {
	
	int		cur_s, cur_t;
	int		prv_t;
	
	int		i;
	
	prv_t = (*w).mintv();
	for ( i = 1; i < n; i++ ) {
		
		cur_s = w[i].s;
		if ( cur_s < prv_t ) cur_s = prv_t;
		
		cur_t = cur_s + w[i].mintv();
		if ( cur_t > w[i].t ) return false;
		
		prv_t = cur_t;
	}
	
	return true;
}

int
main() {
	
	int		n;
	int		i;
	
	while ( scanf("%d", &n), n ) {
		
		for ( i = 0; i < n; i++ ) w[i].init();
		sort(w, w + n);
		
		if ( can_hold_all(n) ) puts("YES");
		else puts("NO");
	}
	
	return 0;
}

单词解释:

integral:adj, 整数的

interrupt:vt, 中断,打断

ceremony:n, 典礼,以示

bless:vt, 祝福,保佑

legend:n, 传奇

priest:n, 牧师,神父

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值