杭電ACM HDU 1006 Tick and Tick

題目大意:輸入D,當時針,分針,秒針兩兩的角度都大於或等於D時,則三者都很開心,問一天中,三者都開心的時間佔了百分之幾?php

具體題目連接:http://acm.hdu.edu.cn/showproblem.php?pid=1006ios

解題思路:less

1、大體的思路爲:spa

     根據條件,因爲精度限制,不能對時分秒都使用窮舉求解,所以採用對時分進行循環窮舉,求出每時每分知足條件的秒數,最後進行求和,指針

列出時間和角度的不等式組,求解關於時間的不等式,求交集,最後對交集求再求並code

2、進一步細化:blog

    1)設未知數:由於咱們要求兩兩之間的角度差,將時間設爲 i 時 j 分 m 秒比較容易計算各個指針所通過的角度以方便求角度差排序

    2)列不等式組:以時針和分針的做爲舉例,時針相對於0時走過的角度-分針相對於0分走過的角度=時針相對於分針的角度差(可正可負),範圍應在D~360-D之間ci

     時針分針: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-Dit

    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\n",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\n",s*100.0/(60*60*12)); 
  }
} 
相關文章
相關標籤/搜索