hdu1006
该问题是我遇到的第一个钟表问题。一开始以为指针是离散的,一格格的走,结果发现精度不够。看了kuangbin大神博客后才知道,原来是要连续处理,解不等式。首先必须清楚以下基本常识:钟上一小格代表6度。时,分,秒的速度比为1:12:720。为了做连续处理,我们只需要枚举每一分钟中符合条件的区间,然后将每分钟的区间长度加起来就得到了总的满足条件的时间。12小时时,三个针再次重合,所以可以以12小时为一个周期来计算即可。始终以12时的位置为0角度。
在任意的h时,m分:
时针走过的角度 hm=h*30+0.5*m+1/120*t;
分钟走过的角度 mm=6*m+0.1*t
秒钟走过的角度 ms=6*t
这时候需要满足三个不等式D<=|hm-mm|<=360-D,D<=|hm-ms|<=360-D,D<=|mm-ms|<=360-D. 而且 0<=t<=60.
以上不等式的解得的交集就是在m时,m分满足条件的区间段。
#define _CRT_SECURE_NO_DEPRECATE #include<iostream> #include<cmath> #include<algorithm> using namespace std; double D; struct Interval{ Interval(double l = 0.0, double r = 0.0){ left = l, right = r; }; double left, right; friend Interval Intesection(Interval X,Interval Y){ Interval res; res.left = max(Y.left, X.left); res.right = min(Y.right, X.right); if (res.left <=res.right) return res; else return Interval(0,0); } friend Interval Intesection(Interval X, Interval Y, Interval Z){ //重载 return Intesection(Intesection(X, Y), Z); } }; Interval const I(0, 60); Interval* inequality(double a, double b){ //解不等式D<=|a+bx|<=360-D和[0,60]交集,保证了b>0 Interval X((D - 360 - a) / b, (360 - D - a) / b); Interval Y(0, (0 - D - a) / b); Interval Z((D - a) / b,60); X = Intesection(X, I); Interval *res=new Interval[2]; res[0] =Intesection(X, Y), res[1] = Intesection(X, Z); return res; } double length(int h, int m){ Interval*s1 = inequality(5.5*m-30 * h, 11.0 / 120); Interval*s2 = inequality(-30 * h - 0.5*m, 6.0 - 1.0 / 120); Interval*s3 = inequality(-6*m, 5.9); double res = 0; for (int i = 0; i < 2;i++) for (int j = 0; j < 2;j++) for (int k = 0; k < 2; k++){ Interval X = Intesection(s1[i], s2[j], s3[k]); res += X.right - X.left; } return res; } int main(){ while (~scanf("%lf", &D) && D != -1){ double res = 0.00; for (int h = 0; h < 12; h++){ for (int m = 0; m < 60; m++){ double x = 5.5*m - 30 * h; if ((abs(x)<D&&abs(x + 5.5)<D) || (abs(x)>360 - D&&abs(x + 5.5)>360 - D)) //可以不要这部分,但是有这部分可以减少不必要的计算,节省时间 continue; res += length(h, m); } } printf("%.3lf\n", res/(6*12*6)); } return 0; }