HDU 1006 解题报告

地址

题意

  • 输入D角度,当时针,分针,秒针两两的角度都大于或等于D时,则三者都很开心,问一天中,三者都开心的时间占了百分之几?

解题思路:

分析

  • 我们都知道12个小时为时针分针秒针的一个周期,所以我们只需要计算12小时内的即可。

错误思路:

  • 遍历12个小时的每秒钟,然后判断夹角,累计求和。
  • 原因:因为精度要求比较高,所以只能求夹角范围。

正确思路:

  • 遍历每时每分里面有多少秒的时间(范围)是开心的,然后累计求和除以总时间。
  • 转化为:假设当前时间为 H:M:X,已知H和M(遍历),求X的范围满足都开心。
  • 时针此时的度数:
    A = 360 12 ( H + M 60 + X 60 60 )
  • 分针此时的度数:
    B = 360 60 ( M + X 60 )
  • 秒针此时的度数:
    C = 360 60 X
  • 所以我们要求三个不等式对应解X的交集
    • D ≤∣ A B ∣≤ 360 D
    • D ≤∣ A C ∣≤ 360 D
    • D ≤∣ B C ∣≤ 360 D
  • 累加每次的交集即为最终Happy时间。

完整代码

#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;

double degree;
struct Interval
{
    double left;
    double right;
};

Interval Intersection2(Interval A, Interval B)
{
    Interval N = {0,0};
    if(A.right <= B.left || B.right <= A.left)
        return N;
    A.left = max(B.left, A.left);
    A.right = min(B.right, A.right);
    if(A.left>A.right)
        return N;
    return A;
}

Interval Intersection3(Interval A, Interval B, Interval T)
{
    return Intersection2(Intersection2(A, B), T);
}

/*
求解 degree<=|kx+b|<=360 - degree
(kx + b) >= degree =>  x>=(degree - b) / k      A
(kx + b) <= -degree =>  x<=(-degree - b) / k    B
(degree - 360) <= (kx + b) <= (360 - degree)    C
D = [0, 60]
(A | B) & C & D
*/
void Slove(double k, double b, Interval *tmp)
{
    Interval A, B, C;
    A.left = (degree - b) / k;
    A.right = 60;

    B.left = 0;
    B.right = (-degree - b) / k;

    C.left = (degree - 360 - b) / k;
    C.right = (360 - degree - b) / k;

    Interval T = {0, 60};

    tmp[0] = Intersection3(A, C, T);
    tmp[1] = Intersection3(B, C, T);
}

/*
时针-分针:  360/12*(h+m/60+x/3600)-360/60*(m+x/60)
            = 30h-11/2*m-11/120*x    (取反,保持x的系数为正,因为要取绝对值所以结果一样)
            = 11/120*x-30h+11/2*m

时针-秒针:  360/12*(h+m/60+x/3600)-360/60*x
            = 719/120*x - 30h - 1/2m

分针-秒针:  360/60*x-360/60*(m+x/60)
            = 59/10*x - 6m
*/
double HappyTime(int hh, int mm)
{
    Interval result[3][2];
    Slove(11.0 / 120, -30.0 * hh + 11.0 / 2 * mm, result[0]);//时针和分针满足要求的解
    Slove(719.0 / 120, -30.0 * hh - 1.0 / 2 * mm, result[1]);//时针和分针满足要求的解
    Slove(59.0 / 10, -6.0 * mm, result[2]);//分针和秒针满足要求的解
    double sum = 0;
    /* 结果就是求交集
    (A|B)&(C|D)&(E|F) = A&C&E + A&C&F + .. // 等于八种情况相加
    */
    for(int x = 0; x < 2; x++)
    {
        for(int y = 0; y < 2; y++)
        {
            for(int z = 0; z < 2; z++)
            {
                Interval T = Intersection3(result[0][x], result[1][y], result[2][z]);
                sum += T.right - T.left;
            }
        }
    }
    return sum;
}

int main()
{
    while(scanf("%lf", &degree) && degree >= 0)
    {
        double happytime = 0;
        for(int hh = 0; hh < 12; hh++)
        {
            for(int mm = 0; mm < 60; mm++)
            {
                double result = HappyTime(hh, mm);
                happytime += result;
            }
        }
        printf("%.3lf\n", happytime * 100 / (12 * 60 * 60));
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/ilovexiaohao/article/details/80859995