题意:一个钟的三个指针在不停的转动,他们厌烦了这样,当他们互相的距离角度大于等于D时,他们会很开心,问一天之中他们happy的时间占总时间的百分比。
分析:只要找到某一分钟内,他们happy的时间,然后钟每过12个小时相当于43200秒复原一次。因此总时间就是43200秒,只要求出在这43200的happy时间,即可求出百分比。枚举12*60分钟,看一分钟内有多少秒是happy的时间,一分钟内解三个不等式可得到区间。
步骤:
1、列出指针(h:m:s)与度数(rh:rm:rs)之间的关系:
秒针:rs=6*s; 分针:rm=6*m+s/10; 时针rh=30*h+0.5*m+s/120;
2、各针之间的角度如下:
分针和秒针:rm-rs=6*m+(0.1-6)*s; 时针和秒针:rh-rs=30*h+0.5*m+(1/120)-6)*s; 时针和分针:rh-rm=30*h+(0.5-6)*m+((1/120)-0.1)*s;
3、指针间的度数要在d到360-d之间,即解三个|ax+b|型的不等式:(s为唯一未知数),当于解方程:d<=a*x+b<=360-d(注意正反) ,并且和 [0,60] 取交集(也即0到60秒)。
4、求出任意一分钟内的秒针取值范围,然后每分钟都求一遍,累加即可得到最终结果。
#include<iostream> using namespace std; struct Range //区间 { double l,r; }; double d; Range sovle(double a,double b) //解方程d<=a*x+b<=360-d,并和[0,60]取交集 { Range ans; if(a>0) { ans.l=(d-b)/a; ans.r=(360-d-b)/a; } else { ans.r=(d-b)/a; ans.l=(360-d-b)/a; } if(ans.l<0) ans.l=0; //求交 if(ans.r>60) ans.r=60; if(ans.l>=ans.r) ans.l=ans.r=0; //空集 return ans; } Range Intersect(const Range& a,const Range& b) //取交集 { Range ans; ans.l=a.l>b.l?a.l:b.l; ans.r=a.r<b.r?a.r:b.r; if(ans.l>=ans.r) ans.l=ans.r=0; //空集 return ans; } double Process(int h,int m) //计算在h时,m分时满足题意的秒数 { double a,b; Range s[3][2]; //区间,包含正反。 Range rans; double ans; int i,j,k; a=1.0/120-0.1; //解方程d<=|hh-mm|<=360-d,hh=30*h+m/2+s/120,mm=6*m+s/10; b=30*h+m/2.0-6*m; s[0][0]=sovle(a,b); s[0][1]=sovle(-a,-b); a=1.0/120-6.0; //解方程d<=|hh-ss|<=360-d,hh=30*h+m/2+s/120,ss=6*s; b=30*h+m/2.0; s[1][0]=sovle(a,b); s[1][1]=sovle(-a,-b); a=0.1-6; //解方程d<=|mm-ss|<=360-d,mm=6*m+s/10,ss=6*s; b=6*m; s[2][0]=sovle(a,b); s[2][1]=sovle(-a,-b); ans=0; for(i=0;i<2;i++) //六个区间,每次选取三个求交集 for(j=0;j<2;j++) //绝对值的式子得到的两个区间要并,三个不同表达式区间要交,所以有六种情况 for(k=0;k<2;k++) { rans=Intersect(Intersect(s[0][i],s[1][j]),s[2][k]); ans+=rans.r-rans.l; } return ans; } int main() { double ans,h,m; while(scanf("%lf",&d)==1 && d!=-1) { ans=0; for(h=0;h<12;h++) //每小时 for(m=0;m<60;m++) //每分钟 ans+=Process(h,m); printf("%.3lf\n",ans*100.0/(60*60*12)); //百分比 } return 0; }
原文地址:http://blog.csdn.net/a809146548/article/details/46400307