HDU1006

       这题是我在HDU上第二次遇到的关于钟表的问题,都很坑人!

        首先,我想大家都会在理解上出问题。其实吧,我觉得这题HDU的思想有问题,钟表是一秒一秒走的,哪有连续时间,表示不解!但题目要求,木有办法了。其次呢,结果要求保留三位有效数字。这也就直接导致了:如果离散的来记录满足条件的时间的话,会在精度上出错!

        现在,来分析下我对这题的做法吧。

题目要求一天(24小时)各个指针的happy time。那么我们该怎么看各个指针呢?不妨让刚开始时各个指针都指在12点的位置,12小时之后又会再回到12点位置,再重复一遍,即可获得24小时总的happy time。显然,记下前12小时的即可啦。

        边贴代码边分析吧。

         ①离散计时(即一秒一秒的计时),结果输入90,输出6.225。(个人认为这种方法没错!)

#include<iostream>
#include<iomanip>
using namespace std;

double calculate(double a,double b)
{
    double temp=(a-b)>0?(a-b):(b-a);
    
    return temp>(360.0-temp)?(360.0-temp):temp;
}

int main()
{
    double degree,flag;
    const double h_degree=360/(12*60*60.0),m_degree=360/(60*60.0),s_degree=360/60.0;
    unsigned int rem_h=1,rem_m=1,rem_s=1,count=0;

    while(cin>>degree && degree>=0.0)
    {
        while(rem_h<=12*60*60)
        {
            if( calculate(rem_h*h_degree,rem_m*m_degree)>=degree )
                if( calculate(rem_m*m_degree,rem_s*s_degree)>=degree )
                    if( calculate(rem_h*h_degree,rem_s*s_degree)>=degree )
                        count++;

            rem_h++;
            rem_m++;
            rem_s++;
            if(rem_s==60+1)
                rem_s=1;
            if(rem_m==60*60+1)
                rem_m=1;
        }

        flag=count/(12*60*60.0)*100.0;
        cout<<setiosflags(ios::fixed);
        cout<<setprecision(3);
        cout<<flag<<endl;

        rem_h=rem_m=rem_s=1;
        count=0;
    }

    return 0;
}


          ②苦于AC无门,也只能找网上大牛们的成品了!(菜鸟的无奈)

           ⑴但第一遍依旧是TLE了,后来明白了可以优化。

#include<iostream>
#include<iomanip>
using namespace std;

//const double w_h=1.0/120,w_m=1./10,w_s=6.0;  //角速度
const double hm=11.0/120,hs=719.0/120,sm=59.0/10;    //相对角速度
const double T_hm=43200.0/11,T_hs=43200.0/719,T_sm=3600.0/59;   //相对周期

inline double min(double a,double b,double c)
{
    double temp=(a>b)?b:a;

    return (c>temp)?temp:c;
}

inline double max(double a,double b,double c)
{
    double temp=(a>b)?a:b;

    return (c>temp)?c:temp;
}

int main()
{
    double degree;
    double x[3],y[3];
    double m[3],n[3];
    double end,begin,sum;

    while(cin>>degree , degree!=-1)
    {
        x[0]=degree/hm;
        x[1]=degree/hs;
        x[2]=degree/sm;

        y[0]=(360-degree)/hm;
        y[1]=(360-degree)/hs;
        y[2]=(360-degree)/sm;

        sum=0.0;
        for(m[0]=x[0],n[0]=y[0];n[0]<=43200.000001;m[0]+=T_hm,n[0]+=T_hm)
        {
            for(m[1]=x[1],n[1]=y[1];n[1]<=43200.000001;m[1]+=T_hs,n[1]+=T_hs)
            {
                for(m[2]=x[2],n[2]=y[2];n[2]<=43200.000001;m[2]+=T_sm,n[2]+=T_sm)
                {
                    begin=max(m[0],m[1],m[2]);
                    end=min(n[0],n[1],n[2]);
                    
                    if(end>begin)
                       sum+=end-begin;
                }
            }
        }

        cout<<setiosflags(ios::fixed)<<setprecision(3)<<sum*100.0/43200<<endl;
    }

    return 0;
}

     

            ⑵AC代码,也用了578MS,险过呀!

              分析下AC代码的思想。

               由于要记录连续时间,那么就利用区间记录,[begin,end]。另外,就拿时针和分针来做例子吧。时针的角速度为w_h=360.0/12*60*60=1.0/120,分针的角速度为w_m=360.0/60*60=1.0/10。两者的相对角速度为w_hm=w_m-w_h,“相对周期”为T_hm=360.0/w_hm。所谓的相对周期就是时针和分针出现重复的相对关系的最小时间。

这样的话就可以把时针和分针,时针和秒针,分针和秒针各自满足条件的集合求交集。显然,代码中利用的是三个for循环来暴力解决。不过有些显然不满足条件的情况即可去除,以减少计算次数。

x[3]和y[3]记录的是第一个开始满足条件的时间和第一个开始不满足条件的时间。m[3],n[3]则是分表根据相对周期来扩大x[3],y[3]以获得所有满足条件的时间集合,并求交集。

#include<iostream>
#include<iomanip>
using namespace std;

//const double w_h=1.0/120,w_m=1./10,w_s=6.0;  //角速度
const double hm=11.0/120,hs=719.0/120,sm=59.0/10;    //相对角速度
const double T_hm=43200.0/11,T_hs=43200.0/719,T_sm=3600.0/59;   //相对周期

inline double min(double a,double b,double c)
{
    double temp=(a>b)?b:a;

    return (c>temp)?temp:c;
}

inline double max(double a,double b,double c)
{
    double temp=(a>b)?a:b;

    return (c>temp)?c:temp;
}

int main()
{
    double degree;
    double x[3],y[3];
    double m[3],n[3];
    double end,begin,sum;

    while(cin>>degree , degree!=-1)
    {
        x[0]=degree/hm;
        x[1]=degree/hs;
        x[2]=degree/sm;

        y[0]=(360-degree)/hm;
        y[1]=(360-degree)/hs;
        y[2]=(360-degree)/sm;

        sum=0.0;
        for(m[0]=x[0],n[0]=y[0];n[0]<=43200.000001;m[0]+=T_hm,n[0]+=T_hm)
        {
            for(m[1]=x[1],n[1]=y[1];n[1]<=43200.000001;m[1]+=T_hs,n[1]+=T_hs)
            {
                if(n[0]<m[1])
                    break;
                if(m[0]>n[1])
                    continue;

                for(m[2]=x[2],n[2]=y[2];n[2]<=43200.000001;m[2]+=T_sm,n[2]+=T_sm)
                {
                    if(n[0]<m[2] || n[1]<m[2])
                        break;
                    if(m[0]>n[2] || m[1]>n[2])
                        continue;

                    begin=max(m[0],m[1],m[2]);
                    end=min(n[0],n[1],n[2]);
                    
                    if(end>begin)
                       sum+=end-begin;
                }
            }
        }

        cout<<setiosflags(ios::fixed)<<setprecision(3)<<sum*100.0/43200<<endl;
    }

    return 0;
}

         欢迎拍砖!

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值