题目大意
小镇有n场婚礼在一天之内矩形,第i场婚礼的开始时间为Si,结束时间为Ti。在每一场婚礼中,有一个重要仪式,即牧师给予两位新人传达主的祝福。对于第i场婚礼,祝福仪式可以在[Si,Ti]中任何时候举行,但是必须超过总时间的一半以上。
小镇只有一位牧师,所有的祝福仪式都必须要他在场。同时,牧师必须在整数时刻开始或者结束祝福仪式,不过他可以在结束一场之后立刻开始另一场。
现在给你所有婚礼的信息,请问是否能够安排好一个祝福仪式的顺序,使得牧师能够给所有新人带去祝福。
思路
刚开始思路就错了,以为按照每场婚礼的开始时刻排序再模拟就行,后来想想完全不对,根本不是那么一回事。例如(1,1000)和(2,500)这两场婚礼,按照开始时刻贪心,那么结果无疑是NO。
正确的方式应该是按婚礼的祝福仪式的“最早的结束时刻t1”或“最晚开始时间t2”排序再模拟。为何如此?因不管从什么时候开始一个祝福仪式,祝福仪式总是包含时间段(t1,t2),我们称(t1,t2)为公共时间段,一场婚礼对应一个公共时间段。若存在一个方案可使所有祝福仪式正常举行,那么所有公共时间段也一定都不会出现重合。也由此可得结论,祝福仪式的举行顺序一定与公共时间段的出现顺序相同。
当然,我们不必将公共时间段的开始和结束时刻都求出来,我们只需求出其中一个即可,再依此对婚礼进行排序,最后按顺序模拟婚礼祝福仪式的举行。若所有祝福仪式都能在时间范围内结束,则说明存在一个方案可使所有祝福仪式按时完成,反之不存在。
代码
#include<iostream> #include<stdio.h> using namespace std; struct point //将每场婚礼的信息封装在结构体中。 { int start; int end; int mid; //mid表示此婚礼的祝福仪式至少持续mid分钟。 }t[100000]; int n; int cmp(const void* m,const void* n) //给婚礼按祝福仪式最早的结束时刻排序。 { return (*(point*)m).start+(*(point*)m).mid-(*(point*)n).start-(*(point*)n).mid; //start+mid表示婚礼最早的结束时刻。 } bool solved() { qsort(t,n,sizeof(t[0]),cmp); long long now=0; for(int i=0;i<n;i++) { now=now>t[i].start?now+t[i].mid:t[i].start+t[i].mid; //now为当前祝福仪式的结束时间。 if(now>t[i].end) //如果祝福仪式结束时间晚于婚礼结束时间。 return false; } return true; } int main() { while(scanf("%d",&n)&&n) { for(int i=0;i<n;i++) { scanf("%d%d",&t[i].start,&t[i].end); t[i].mid=(t[i].end-t[i].start)/2+1; //注意题干中的条件,祝福仪式至少要“大于”婚礼总时间的一半。 } printf("%s\n",solved()?"YES":"NO"); } }