码迷,mamicode.com
首页 > 其他好文 > 详细

HDU ACM 1006 Tick and Tick

时间:2015-06-07 15:56:17      阅读:141      评论:0      收藏:0      [点我收藏+]

标签:c   c++   acm   算法   数学   

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


HDU ACM 1006 Tick and Tick

标签:c   c++   acm   算法   数学   

原文地址:http://blog.csdn.net/a809146548/article/details/46400307

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!