题意:一个钟的三个指针在不停的转动,他们厌烦了这样,当他们互相的距离角度大于等于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