hdu1006

#include <iostream>
using namespace std;
const int MAXN = 12 * 60 * 60;
const double s = 6;//秒针的角速度为6°/s
const double m = 1.0 / 10;//分针的角速度为1/10°/s
const double h = 1.0 / 120;//时针的角速度为1/120°/s
const double ms = s - m;//分针秒针的相对角速度,即角速度之差
const double hs = s - h;//时针秒针的相对角速
const double hm = m - h;//时针分针的相对角速
const double tms = 1 / ms;//分针秒针分离1°所需的时间
const double ths = 1 / hs;//时针秒针分离1°所需的时间
const double thm = 1 / hm;//时针分针分离1°所需的时间
//求任意两指针从重合到分离n°的时间,有些类似在直线上的s = vt,n°即s,两指针角速度之差即v
//可以归类为循环追及问题
//三个两两指针分为一组
//取三个两两指针分离n°所需时间的最大值,即最迟实现相对分离为n°的那组
//再取三个两两指针分离360 - n°,亦即反向分离n°(表是个环)所需时间的最小值,即最早要满足相对分离为n°的那一组
//最迟和最早分别对应的时刻,所以中间的这段区间就是满足三个指针都相对分离至少n°的时间段
//一天为24小时,但时针分针秒针从重合到再次重合只需12小时,所以就可简化为12小时,因为题目中要求的是百分比,而不是总时间,要求总时间的话就累加后乘个2就可以
//三层循环,属于暴力枚举,如果不优化的话可能过不了,这就需要消除一些不必要的条件
//i,j,k是按照各组指针分离1°所需的时间从大到小组织的(因为内循环最先执行,所以最小的时间对应最内层的循环)
//(时针分针秒针三者都是动态的)时针分针分离1°所需时间最大,约为10.90s,然后是时针秒针,约为5.99s,最后是分针秒针,为5.9s,分离1°所需时间最小
//故在第三层循环中当分针秒针组(第三层)分离n°的起始时刻大于第二层即时针秒针组满足分离n°的终止时刻,就可以跳出这层循环,即break,因为k相对于j一直在自增,所以之后的时刻都不会满足条件
//在第三层循环中当时针秒针组(第二组)的起始时刻和对应的时针分针组(第一层)的终止时刻也出现上述情况时(j相对于i也在自增),break
//在第三层循环中当时针秒针组(第二层)分离n°的起始时刻大于第三层即分针秒针组满足分离n°的终止时刻,可以continue,但不可以break,因为k相对于j在自增,很有可能会出现起始时刻小于终止时刻的情况,这就需要累加这个时间段
//同样的,在第三层循环中当时针分针组(第一层)的起始时刻与对应的时针秒针组(第二层)的终止时刻也出现上述情况时,需要continue而不是break
//类似的,在第二层循环中就只用考虑两种情况
//在第二层循环中当时针分针组(第一层)分离n°的起始时刻大于第二层即时针秒针组满足分离n°的终止情况,需要continue,因为j相对于i在自增,反之时针秒针组分离n°的起始时刻大于时针分针组就只能break掉了,因为再往下执行,怎么都不会出现交集
int main(){
    int n;
    while(scanf("%d", &n) && n != -1){
        double ans = 0;
        //i, j, k代表的是每次时针分针秒针两两重合的时间
        //i, j, k的排列是按照其相对角速度的从大到小排列的
        for(double i = 0; i <= MAXN; i += 360 * thm){//360 * thm 即时针分针再次重合的时间(相对周期)
            for(double j = 0; j <= MAXN; j += 360 * ths){
                //此循环中只有变量j在迭加
                //消除不必要的条件
                if(i + n * thm > j + (360 - n) * ths)
                    continue;//j + (360 - n) * thm可能超过i + n * thm,故continue
                if(j + n * ths > i + (360 - n) * thm)
                    break;//i + (360 - n) * thm不可能再超过j + n * ths,故break
                for(double k = 0; k <= MAXN; k += 360 * tms){
                    if((i + n * thm > j + (360 - n) * ths) || (j + n * ths > k + (360 - n) * tms))
                        continue;
                    if((j + n * ths > i + (360 - n) * thm) || (k + n * tms > j + (360 - n) * ths))
                        break;
                    //n * thm 即时针分针分离n°时所需的时间
                    //(360 - n) * thm 即时针分针分离-n°所需的时间
                    double begin = max(i + n * thm, max(j + n * ths, k + n * tms));
                    double end = min(i + (360 - n) * thm, min(j + (360 - n) * ths, k + (360 - n) * tms));
                    if(end > begin)
                        ans += end - begin;
                }
            }
        }
        printf("%.3lf\n", 100 * ans / MAXN);//求得的时间段除以总时间在乘上100,求得百分比
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值