• Tick and Tick


      第一次写博客,此文是关于HDOJ 1006题Tick and Tick的学习与整理;自己捣鼓了好几天,看了网上的一些解题思路最后终于琢磨出来,希望对大家有所帮助。

    Problem Description
    The three hands of the clock are rotating every second and meeting each other many times everyday. Finally, they get bored of this and each of them would like to stay away from the other two. A hand is happy if it is at least D degrees from any of the rest. You are to calculate how much time in a day that all the hands are happy.

      对于该题起初的设想是在12小时内(对称结构)遍历秒指针43200次,而此做法无法达到题目的精度要求,不得不放弃;后面想想确实如此,若按秒为单位由于1秒经过的是6º,从而会有很大的误差。

      既然此路不通,原因也很明确(精度不够);便换一条思路,考虑到指针的夹角是关于时、分、秒的线性函数,当时、分确定便可得到关于秒的线性不等式组;所以回退一步遍历12*60分钟,从而计算计算出每一分钟内happyTime的区间范围(还是以秒为单位);最后计算出总的happyTime区间占总的区间大小43200的比例即可。要实现此目标首先便需要计算任一时刻H:M:S(0 <= H < 12, 0 <= M < 60, 0 <= S < 60, H,M皆为整数, S为实数)下各指针相对于0时刻(统一参照点)的夹角,简单分析可得各夹角分别为HAngle = 30 * H + (1/2) * M + (1/120) * S;MAngle = 6 * M + (1/10) * S;SAngle = 6 * S;而happyTime的定义是要求各指针夹角均不小于D,之后只需求解关于S的不等式组:D≤|HAngle - MAngle|≤360 - D ; D≤|HAngle - SAngle|≤360 - D ; D≤|MAngle - SAngle|≤360 - D。所得到的结果保存在数组Seg[3][2]中,最终的结果为(Seg[0][0]∪Seg[0][1])∩(Seg[1][0]∪Seg[1][1])∩(Seg[2][0]∪Seg[2][1])其中对于绝对值的解集Seg[0][0]∩Seg[0][1] = 0(之后求解有用)

      既然思路明确,那么此题的关键便是求解不等式组,对于上述六个数组分别用a,b,c,d,e,f代替(为求方便);不等式组的解最终可以转换为

    (a∩c∩e)∪(b∩c∩e)∪(a∩d∩e)∪(b∩d∩e)∪(a∩c∩f)∪(b∩c∩f)∪(a∩d∩f)∪(b∩d∩f),且其中(a∩b = c∩d = e∩f = 0),即上述8个不等式互不相交;所有S的解集为:

    (a∩c∩e) + (b∩c∩e) + (a∩d∩e) + (b∩d∩e) + (a∩c∩f) + (b∩c∩f) + (a∩d∩f) + (b∩d∩f)

    以下是本人AC代码,仅供参考:

    #include<iostream>
    #include<iomanip>
    using namespace std;
    
    //区间结构体
    struct Interval
    {
        double left;
        double right;
    };
    
    //求解区间1
    Interval Solving1(double coef , double constant , double Degree)
    {
        Interval result;
        double _left = (Degree + constant) / coef;
        double _right = (360 - Degree + constant) / coef;
        if(_left < 0)
            _left = 0;
        if(_right > 60)
            _right = 60;
        if(_left > _right)
            _left = _right = 0.0;
        result.left = _left;
        result.right = _right;
        return result;
    }
    //求解区间2
    Interval Solving2(double coef , double constant , double Degree)
    {
        Interval result;
        double _left = (Degree + constant - 360) / coef;
        double _right = (constant - Degree) / coef;
        if(_left < 0)
            _left = 0;
        if(_right > 60)
            _right = 60;
        if(_left > _right)
            _left = _right = 0.0;
        result.left = _left;
        result.right = _right;
        return result;
    }
    
    //求交集
    Interval operator * (Interval a , Interval b)
    {
        Interval result;
        if(a.left < b.left)
            result.left = b.left;
        else
            result.left = a.left;
        if(a.right < b.right)
            result.right = a.right;
        else
            result.right = b.right;
        if(result.left > result.right)
            result.left = result.right = 0.0;
        return result;
    }
    
    int main()
    {
        double D , coef , cont;
        Interval inter[3][2];
        while (cin >> D && (D != -1))
        {
            double sum = 0.0;
            for(int H = 0 ; H < 12 ; ++ H)
            {
                for(int M = 0 ; M < 60 ; ++ M)
                {
                    //求符合条件的区间范围
                    //时、分指针夹角
                    coef = 11.0 / 120;
                    cont = 30.0 * H - 5.5 * M;
                    inter[0][0] = Solving1(coef , cont , D);
                    inter[0][1] = Solving2(coef , cont , D);
                    //时、秒指针夹角
                    coef = 719.0 / 120;
                    cont = 30.0 * H + 0.5 * M;
                    inter[1][0] = Solving1(coef , cont , D);
                    inter[1][1] = Solving2(coef , cont , D);
    
                    //分、秒指针夹角
                    coef = 5.9;
                    cont = 6.0 * M;
                    inter[2][0] = Solving1(coef , cont , D);
                    inter[2][1] = Solving2(coef , cont , D);
    
                    //求交集
                    for(int i = 0 ; i < 2 ; ++ i)
                        for(int j = 0 ; j < 2 ; ++ j)
                            for(int k = 0 ; k < 2 ; ++ k)
                            {
                                Interval Seg = inter[0][i] * inter[1][j] * inter[2][k];
                                sum += (Seg.right - Seg.left);
                            }    
                }
            }
            cout << setiosflags(ios::fixed) << setprecision(3) << sum / 432.0 << endl;
        }
        system("pause");
        return 0;
    }

    参考文章:http://hi.baidu.com/guoxiangke2008/item/58f27b3233c80cc22e8ec225?qq-pf-to=pcqq.c2c

  • 相关阅读:
    这款开源测试神器,圆了我玩游戏不用动手的梦想
    在spring容器中对中间件bean进行替换
    java agent调试
    linux查看进程的打开文件数
    Ubuntu 下的 Git 在 SSH 协议下使用代理
    GO语言程序查询数据库字段为空遇到的几个问题总结
    Vue3学习(十)之 页面、菜单、路由的使用
    寻找写代码感觉(十)之SpringBootAOP的使用
    寻找写代码感觉(九)之SpringBoot拦截器的使用
    寻找写代码感觉(八)之SpringBoot过滤器的使用
  • 原文地址:https://www.cnblogs.com/winstic/p/3951488.html
Copyright © 2020-2023  润新知