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
", res/(6*12*6));
    }
    return 0;
}
原文地址:https://www.cnblogs.com/td15980891505/p/5564130.html