题目大意:
今天是神父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, 牧师,神父