杭电-1006 Tick and Tick
这题需要一些耐心,准备好了就来吧。
我们理解题目意思的时候注意,
A hand is happy if it is at least D degrees from any of the rest.
这句话并不是谷歌翻译的那样
“如果一只手与其余任何一只手至少有D度,那它就是快乐的”
其实题目要求是与其余所有的手(2只)都相距D度,它才是快乐的。
另外,
1,时间是连续的,三根指针之间的位置是有关系的,不能随意摆放。
2,一个圈是360度
指针之间大于D度的情况,可以描述如图
首先想到的思路是穷举所有时间,将一天24小时指针的位置全部记录下来,然后计算出结果。
另外由于24小时实际是在表盘上走了2圈,我们可以简化为求1圈的数据,即12小时指针的情况就行了。
但是按秒穷举所有时间实在太慢,我参考了前辈的思路:
零点时,三针合一,
两两指正的距离为0,
然后指针慢慢分开,
不难想象,当两两指针分开距离 全部都 超过D时,满足题目条件,
然后它们会再度重合,重新开始。(可以联系钟表想象一下其它三针合一的情况)
这样,在 重合 -> 再次重合 的过程中,有一段连续的距离是满足题目条件的。
这个距离可以这样描述 :
两两指针分离到D所用时间的最大值 (3个指针,两两看做一组)-------->
两两指针分离到D后,继续分离,到360-D距离所用时间的最小值(360-D其实就是从圆的另一端看,两指针距离小于D的情况,此时刚好不满足题目要求)
之所以是最大值是因为题目要求 全部距离D以上 ,所以必须等那三个组合中最慢的那一个完全分开D距离。
之所以是最小值同理,一旦有一个组合不满足 距离大于D 的要求,则整个系统不满足题目要求。
故
我们可以遍历所有指针重复的情况,并在从重复 走向 下一次重复的过程中,取符合题目要求的时间段,继而计算出结果。
具体思路见代码(已AC):
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=12*60*60;
double Max(double a,double b,double c)
{
return max(max(a,b),c);
}
double Min(double a,double b,double c)
{
return min(min(a,b),c);
}
int main(){
double D;
while(scanf("%lf",&D)&&D!=-1){
double vh,vm,vs;//角速度,per秒
vs = 6.0;
vm = 1.0/10;
vh = 1.0/120;
double i,j,k;
double ans=0,p,q;
//两两指针之间运动到完全重合的时间————每过这么一段时间,该两指针就会重合
double t_hm,t_hs,t_ms,a[7];
t_hm = 360/(vm-vh);
t_hs = 360/(vs-vh);
t_ms = 360/(vs-vm);
//两两指针运动 出 到相距为d的时间
a[0] = D/(vm-vh);
a[1] = D/(vs-vh);
a[2] = D/(vs-vm);
//两两指针运动 回 到相距为d的时间
a[3] = (360-D)/(vm-vh);
a[4] = (360-D)/(vs-vh);
a[5] = (360-D)/(vs-vm);
/*
每一次两两指针一出一回之间,必有一段连续的距离大于D,当任意两两指针之间的距离都大于D时,满足题目要求
再进一步分析可知,
“两两指针运动 出 到相距为d的时间” 应取最大,因为题目要求所有的指针都happy
“两两指针运动 回 到相距为d的时间” 应取最小,因为一旦有一对指针“回来了(相距距离小于d)”,则不满足大家都happy的题目要求
*/
for(i=0;i<=1.0*maxn;i+=t_hm)
for(j=0;j<=1.0*maxn;j+=t_hs){
if(j+a[1]>i+a[3])break;//p>=j+a[1]&&q<=i+a[3]=>p>q=>无效
if(i+a[0]>j+a[4])continue;
for(k=0;k<=1.0*maxn;k+=t_ms)
{
// if(k+a[2]>i+a[3]||k+a[2]>j+a[4])break;
// if(i+a[0]>k+a[5]||j+a[1]>k+a[5])continue;
p=Max(i+a[0],j+a[1],k+a[2]);//在这三个时间段刚好完成分离n度,所以取最大值才能保证全都分离n以上
q=Min(i+a[3],j+a[4],k+a[5]);//在这三个时间段刚好完成合并n度,所以取最小值才能保证全都未合并到n以内
// cout << p <<endl<< q <<endl;
if(q > p){
// cout << ans << endl;
ans+=q-p;
}
}
}
printf("%.3lf\n",100.0*ans/maxn);
}
return 0;
}
由于本人技术比较菜,调Bug调到怀疑自我,导致此代码和其它来源代码部分雷同,见谅。