題目大意:輸入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)); } }