HDU 1006时钟三针相差d度问题(详解)

Time Limit: 10000/5000 MS (Java/Others)
Tick and Tick
Time Limit: 2000/1000 MS (Java/Others)

Memory Limit: 65536/32768 K (Java/Others)

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.
Input
The input contains many test cases. Each of them has a single line with a real number D between 0 and 120, inclusively. The input is terminated with a D of -1.
Output
For each D, print in a single line the percentage of time in a day that all of the hands are happy, accurate up to 3 decimal places.
Sample Input
0
120
90
-1
Sample Output
100.000
0.000
6.251

原博主https://blog.csdn.net/w_linux/article/details/75642463
总体思路在原博主的博客里有写,一种比较基础的罗列枚举方法,如果原博主的内容你能直接看懂就不用来费时间在这篇文章上了。
如果你看的不太明白,又一定想要理解的话,说不定这篇文章可以对你有一点帮助。
(我也不明白为什么有更简单易懂的方法,但我仍然浪费多几个小时来理解这种方法有什么意义)
像我这种笨脑子想把东西看懂就得一点一点备注吧
写这个只是为了自己记录一下第一次费劲思考的问题(尽情嘲笑我吧)
看了好久才终于理解了这位博主的代码,在这里也几乎没有改动,仅仅是把原博主的代码备注的详细一些,希望想透彻理解这种方法的人能有帮助,同时也确认自己真正的理解透彻了

/*有关break和continue
利用三重循环最重要的一点是要明白
开始的bs_m肯定是小于结束的em_h和es_h(其他同理)用break
但是bm_h和bs_h是有可能大于es_m(其他同理)用continue
*/

对以上内容的个人较为详细的理解
【第二个break和continue】//以下内容在代码中会再次注释

当(秒针/分针)开始happy的时间(一般是最迟)
大于【(分针/时针)/或者/(秒针/时针)】结束happy的时间的时候 (应该是先大于前者)
{在此次(秒针/分针)的happy时间段里,【(分针/时针)/或者/(秒针/时针)】都不会再happy
所以这一轮循环结束}——————>用break

当 【(分针/时针)/或者/(秒针/时针)】开始happy的时间(一般比较早)
大于(秒针/分针)开始happy的时间的时候
{在【(分针/时针)/或者/(秒针/时针)】此次happy的时间段里
后面还可能有有(秒针/分针)开始happy的时间} ——————>用continue
*/

/*continue是在这个循环中进还未开始检索到revelry time时的操作
break是在这个循环中revelry time已经全部检索完毕后的操作
*/

#include<iostream>
#include<stdio.h>
using namespace std;
inline double max(double a,double b,double c) 
{ 
a= a > b ? a: b; 
a= a > c ? a: c; 
return a; } 
inline double min(double a,double b,double c) { 
a= a < b ? a: b; 
a= a < c ? a: c; 
return a; } //此处换了一种求最大最小值的方法不过作用一样并不影响
int main()
{
double s=6.0;
double m=0.1;
double h=1./120;
//角速度之差
double s_m=59./10;//5.9 
double s_h=719./120;//5.992
double m_h=11./120;//0.061


//周期(即两针需要多久出现夹角循环的周期)
//即重合到下一次重合所需的时间(周期) 
double Ts_m=360./s_m;//61.016
double Ts_h=360./s_h;// 60.08 
double Tm_h=360./m_h;//3956.043 


double d;
while(scanf("%lf",&d))
{
    double bs_m,bs_h,bm_h,es_m,es_h,em_h;
    double i,j,k; //分别为重合时间(从0开始,一次一次加周期)  
    double beginmax,endmin;
    double total=0;
    //计算第一次满足条件的时间
    bs_m=d/s_m;//两针分离到n度的时间
    bs_h=d/s_h;
    bm_h=d/m_h;

    /*cout<<"bs_m:"<<bs_m<<endl; 
    cout<<"bs_h:"<<bs_h<<endl; 
    cout<<"bm_h:"<<bm_h<<endl; */ 

    //计算第一次不满足条件的时间,就是两针分离了360-d度所需要的时间(之后就不符合了)
    es_m=(360-d)/s_m;//Ts_m-bs_m
    es_h=(360-d)/s_h;
    em_h=(360-d)/m_h;

   /* cout<<"es_m:"<<es_m<<endl; 
    cout<<"es_h:"<<es_h<<endl; 
    cout<<"em_h:"<<em_h<<endl;*/ 

    if(d==-1)
    {
        break;
    }
  //对时间进行一步步筛选 
    for(i=0;i<43200*1.0;i+=Tm_h)//每次(时针/分针)mh重合的时间 【循环1】 
    {                           

        for(j=0;j<43200*1.0;j+=Ts_h)//每次(时针/秒针)sh重合的时间 【循环2】 
        { 

            if(j+bs_h>i+em_h)break;
            /*(时针/秒针)sh开始happy的时间大于(时针/分针)mh结束happy的时间 
            在这一轮(时针/分针)mh的happy时间里【循环1】,(时针/秒针)sh不可能再happy //就是不可能有 revelry 
            所以用break */
            if(i+bm_h>j+es_h) continue;
            /*(时针/分针)mh开始happy的时间大于(时针/秒针)sh结束happy的时间
            在这一次(时针/秒针)sh的循环里【循环2】 (时针/分针)mh将不会有happy时间 //就是不可能有 revelry 
            但是 
            在这一轮(时针/分针)mh的happy时间里【循环1】,(时针/秒针)sh还可能会happy
            (虽然这次循环2不可能所以continue跳过这次循环2) */

            for(k=0;k<43200*1.0;k+=Ts_m)  // 每次(秒针/分针)sm重合的时间 【循环3】 
            {
                if(k+bs_m>i+em_h||k+bs_m>j+es_h) break;
                /*如果sm开始happy的时间大于(mh或者sh结束happy的时间)
                则在这一次 sm的happy时间里【循环3】里 不可能有 revelry //同时这次循环1,2都不可能再有revelry了  
                */ 

                if(i+bm_h>k+es_m||j+bs_h>k+es_m)continue;
                /*(mh或者sh开始happy的时间)大于这个循环3里sm结束happy的时间 
                则在这个循环3里不会有revelry time
                但是
                在这次的【循环2】下,下一个【循环3】里sm结束happy的时间可能会比mh/sh开始happy的时间短//仍然可能会出现revelry 
                所以continue继续循环3 
                */ 


                //得到区间[max,min]【所有循环筛选下,真正需要】 
                beginmax=max(i+bm_h,j+bs_h,k+bs_m);//(sm,mh,hs三者两两)分别开始happy的时间
                                               //最大能保证全部分离到d度以上 (全部都开始happy)                                  
                endmin=min(i+em_h,j+es_h,k+es_m);  //(sm,mh,sh三者两两)分别结束happy的时间 
                                   //最小能保证全部都未达到小于d度数 (只要有一个刚刚结束happy) 

                total+=(endmin-beginmax);//把符合要求的 revelry time(狂欢时间) 全部相加 
            }
        }
    }
    printf("%.3lf\n",total*100.0/43200.0);//精确到小数点后三位 
}
return 0;}

代码注释加的繁琐甚至有些啰嗦,遇到类似的多变量同时变化的问题就是容易晕头转向,希望以后能有长进吧。
如果还有什么不理解可以在下方提问,希望对你们有帮助。

发布了4 篇原创文章 · 获赞 1 · 访问量 106

猜你喜欢

转载自blog.csdn.net/jxb727098/article/details/81482004
hdu