zoukankan      html  css  js  c++  java
  • 杭电ACM HDU 1006 Tick and Tick

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

    具体题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1006

    解题思路:

    一、大致的思路为:

         根据条件,由于精度限制,不能对时分秒都使用穷举求解,因此采用对时分进行循环穷举,求出每时每分满足条件的秒数,最后进行求和,

    列出时间和角度的不等式组,求解关于时间的不等式,求交集,最后对交集求再求并

    二、进一步细化:

        1)设未知数:因为我们要求两两之间的角度差,将时间设为 i 时 j 分 m 秒比较容易计算各个指针所经过的角度以方便求角度差

        2)列不等式组:以时针和分针的作为举例,时针相对于0时走过的角度-分针相对于0分走过的角度=时针相对于分针的角度差(可正可负),范围应在D~360-D之间

         时针分针:D<=|360/12*(i+j/60+m/3600)-360/60*(j+m/60)|<=360-D
         时针秒针:D<=|360/12*(i+j/60+m/3600)-360/60*m|<=360-D
         分针秒针:D<=|360/60*(j+m/60)-360/60*m|<=360-D

        3)求解不等式,对于i,j使用列举,未知数为m,因此可所有不等式解释为D<=|a*x+b|<=360-D;

         该绝对值不等式解集为  [min((D-b)/a, (360-D-b)/a) , max((D-b)/a, (360-D-b)/a)]   U  [min((-D-b)/a, (-360+D-b)/a) , max((-D-b)/a, (-360+D-b)/a)],再与0~60求交集

        4)对不等式组求解,即求三个不等式解的交集

        5)对于以上得到的交集,再求各个交集的并集即是每分钟里满足条件的时间,之后的步骤详见代码

    /*时针分针的角度差:360/12*(i+j/60+m/3600)-360/60*(j+m/60)
      时针秒针的角度差:360/12*(i+j/60+m/3600)-360/60*m
      分针秒针的角度差:360/60*(j+m/60)-360/60*m
    */
    #include<iostream>
    #include<cmath>
    #include <algorithm>
    using namespace std;
    struct set
    {
        double l;//存储解集的左边界 
        double h;//存储解集的右边界 
    };
    
    void solve(set *x,double a,double b,double D)
    {//求解绝对值不等式:D<=|a*x+b|<=360-D,并将所得解和0~60求交集 
        double u=(D-b)/a;double v=(360-D-b)/a;
        x[0].l = max(0.0,min(u,v));
        x[0].h = min(60.0,max(u,v));
        if(x[0].l > x[0].h )//交集为空 
           x[0].l=x[0].h=0;
        
        u=(-D-b)/a;v=(D-360-b)/a;
        x[1].l = max(0.0,min(u,v));
        x[1].h = min(60.0,max(u,v));
        if(x[1].l > x[1].h )//交集为空 
           x[1].l=x[1].h=0;
    }
    
    set intersection(set x1,set x2,set x3)
    {//求三者的交集 
        set y;
        y.l=max(x1.l,max(x2.l ,x3.l));
        y.h=min(x1.h,min(x2.h,x3.h));
        if(y.l>y.h )
          y.l=y.h=0;//交集为空 
        return y;
    }
    int main()
    {
      double D;
      while(cin>>D&&D!=-1)
      {
          double s=0;//记录三者都开心的秒数 
          set x[3][2],y[8];
          /*求解每小时每分钟符合条件的秒数*/ 
          for(int i = 0 ; i < 12 ;i++)
          {
              for(int j=0 ; j < 60 ; j++)
              {
                  double a = 360.0/12*1/3600-360.0/60*1/60;//常数的小数点不能少
                  double b = 360.0/12*(i+j/60.0)-360.0/60*j;
                  solve(x[0],a,b,D);//时针和分针满足要求的解
                   
                  a=360.0/12*1/3600-360.0/60;
                  b=360.0/12*(i+j/60.0);
                  solve(x[1],a,b,D);//时针和秒针满足要求的解 
                  
                  a=360.0/60*1/60-360.0/60;
                  b=360.0/60*j;
                  solve(x[2],a,b,D);//分针和秒针满足要求的解
                  
                //求交集
                int k=0; 
                for(int p=0;p<2;p++)
                    for(int q=0;q<2;q++)
                        for(int r=0;r<2;r++)
                        {//三层循环来表示x[0],x[1],x[2]中各选一个进行组合,
                          //并求其交集 
                            y[k]=intersection(x[0][p],x[1][q],x[2][r]);
                            //因为y[0~7]集合都是不相交的,所以并集可以直接相加(当没有仔细考虑到这些集合是不相交的时,可用接下来的代码2,比较麻烦,但是也有可以借鉴的地方)
                            s+=y[k].h -y[k].l ;
                            k++;
                        }
                }
          printf("%.3lf
    ",s*100.0/(60*60*12)); 
      }
    } 

    #include<iostream>
    #include<cmath>
    #include <algorithm>
    using namespace std;
    struct set
    {
        double l;//存储解集的左边界 
        double h;//存储解集的右边界 
    };
    
    void solve(set *x,double a,double b,double D)
    {//求解绝对值不等式:D<=|a*x+b|<=360-D,并将所得解和0~60求交集 
        double u=(D-b)/a;double v=(360-D-b)/a;
        x[0].l = max(0.0,min(u,v));
        x[0].h = min(60.0,max(u,v));
        if(x[0].l > x[0].h )//交集为空 
           x[0].l=x[0].h=0;
        
        u=(-D-b)/a;v=(D-360-b)/a;
        x[1].l = max(0.0,min(u,v));
        x[1].h = min(60.0,max(u,v));
        if(x[1].l > x[1].h )//交集为空 
           x[1].l=x[1].h=0;
    }
    
    set intersection(set x1,set x2,set x3)
    {//求三者的交集 
        set y;
        y.l=max(x1.l,max(x2.l ,x3.l));
        y.h=min(x1.h,min(x2.h,x3.h));
        if(y.l>y.h )
          y.l=y.h=0;//交集为空 
        return y;
    }
    
    bool less1(const set &y1, const set &y2) 
    {
            return y1.l < y2.l;
    }
    int main()
    {
      double D;
      while(cin>>D&&D!=-1)
      {
          double s=0;//记录三者都开心的秒数 
          set x[3][2],y[8];
          /*求解每小时每分钟符合条件的秒数*/ 
          for(int i = 0 ; i < 12 ;i++)
          {
              for(int j=0 ; j < 60 ; j++)
              {
                  double a = 360.0/12*1/3600-360.0/60*1/60;
                  double b = 360.0/12*(i+j/60.0)-360.0/60*j;
                  solve(x[0],a,b,D);//时针和分针满足要求的解
                   
                  a=360.0/12*1/3600-360.0/60;
                  b=360.0/12*(i+j/60.0);
                  solve(x[1],a,b,D);//时针和秒针满足要求的解 
                  
                  a=360.0/60*1/60-360.0/60;
                  b=360.0/60*j;
                  solve(x[2],a,b,D);//分针和秒针满足要求的解
                  
                //求交集
                int k=0; 
                for(int p=0;p<2;p++)
                    for(int q=0;q<2;q++)
                        for(int r=0;r<2;r++)
                        {//三层循环来表示x[0],x[1],x[2]中各选一个进行组合,
                          //并求其交集 
                            y[k]=intersection(x[0][p],x[1][q],x[2][r]);
                            k++;
                        }
                //求并集
                sort(y,y+7,less1);//排序 
                set c=y[0];
                for(int i=1;i<=7;i++)
                {
                    if(y[i].l<=c.h&&y[i].h>c.h)
                    {
                        c.h=y[i].h ;
                    }
                    else if(y[i].l>c.h)
                    {
                        s+=c.h-c.l;
                        c.l=y[i].l;
                        c.h=y[i].h;
                    }
                }
                s+=c.h-c.l;
            }
        }
          printf("%.3lf
    ",s*100.0/(60*60*12)); 
      }
    } 

        

  • 相关阅读:
    C 扩展库
    访问nginx时验证密码
    关于redis闪退的案例
    查看进程的准确启动时间
    Ansible随笔8
    Ansible-随笔-7
    运维基本工作
    随笔-ansible-6
    随笔-ansible-5
    随笔-ansible-4
  • 原文地址:https://www.cnblogs.com/denghui666/p/7622098.html
Copyright © 2011-2022 走看看