HDOJ 1006 Tick and Tick

这道题比较自己看到后比较迷茫,在网上搜了下,发现大部分都是直接给出代码,具体解题思路不容易一下看明白,自己花了些时间,将思路整理了下。

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1006

        这道题目需要求时针、分针、秒针之间的间隔区间大于某个角度(这个角度由用户输入)的总时间占一天之中总时间的比例。

可以这样理解:

1、我们只需要算出时钟从12点整(3个指针重合),到下一次在12点整(三个指针再次重合)这12个小时的时间过程中,这3个指针之间的区间间隔大于指定角度的时间(即秒数)即可。

2、既然是算秒数,我们可以算这12个小时,也就是在这720分钟当中,每分钟有多少秒这三个指针的位置符合要求。

3、于是,我们就需要计算在h:m:s,即h时m分s秒时刻,这三个指针偏离12点整位置的角度(因为这样便于计算这三个指针的相对角度差,即它们相距的区间):

时针偏离的角度为:hAngle = 30*h + 0.5*m + (1/120)*s

分针偏离的角度为:mAngle = 6*m + 0.1*s

秒针偏离的角度为:sAngle = 6*s

4、接下来,我们计算这三个指针的角速度:

时针的角速度为:hV = 1/120度每秒

分针的角速度为:mV = 0.1度每秒

秒针的角速度为:sV = 6度每秒

5、这样,我们就可以根据上式算出h时m分这一分钟内,有多少秒使这三个指针的位置是符合要求的。

假如用户输入的区间间隔是degree度,位置要求是这样的:1) degree<=|hAngle-mAngle|<=360-degree   2) degree<=|hAngle-sAngle|<=360-degree   3) degree<=|mAngle-sAngle|<=360-degree

所以在这一分钟之内,满足上面三个等式的时间(即秒数),为我们所求。

6、这样我们就能得到3个s的区间,而这个区间必须与[0,60]取交集,因为这是计算的一分钟内的秒数,不可能超过60秒。

7 、对这3个区间求交集,即可得到所需的秒数。


#include <stdio.h>

#define hAngle h*30.0+m*0.5+s/120.0
#define mAngle m*6.0+s*0.1
#define sAngle s*6.0

#define hV 1.0/120
#define mV 0.1
#define sV 6.0

typedef struct{
	double l;
	double r;
}interval;

double degree;
double s = 0;

interval solveInequality(double vDiff, double angleDiff){

	//解不等式:degree<=|vDiff*s+angleDiff|<=360-degree
	interval in;
	if(vDiff > 0){
		in.l = (degree-angleDiff)/vDiff;
		in.r = (360-degree-angleDiff)/vDiff;
	}
	else{
		in.l = (360-degree-angleDiff)/vDiff;
		in.r = (degree-angleDiff)/vDiff;
	}

	if(in.l < 0){
		in.l = 0;
	}
	if(in.r > 60){
		in.r = 60;
	}
	if(in.l >= in.r){
		in.l = in.r = 0;
	}

	return in;
}

interval intersection(interval a, interval b){
	 
	interval c;

	if(a.l > b.l){
		c.l = a.l;
	}
	else{
		c.l = b.l;
	}

	if(a.r < b.r){
		c.r = a.r;
	}
	else{
		c.r = b.r;
	}

	if(c.l >= c.r){
		c.l = c.r = 0;
	}

	return c;
}

double happyTime(int h, int m){

	double vDiff, angleDiff;
	double result=0;
	interval ss[3][2];
	interval in;
	int i, j, k;

	//解不等式degree<=|hAngle-mAngle|<=360-degree
	vDiff = hV- mV;
	angleDiff = hAngle - mAngle;
	ss[0][0] = solveInequality(vDiff, angleDiff);
	ss[0][1] = solveInequality(-vDiff, -angleDiff);

	//degree<=|hAngle-sAngle|<=360-degree
	vDiff = hV- sV;
	angleDiff = hAngle - sAngle;
	ss[1][0] = solveInequality(vDiff, angleDiff);
	ss[1][1] = solveInequality(-vDiff, -angleDiff);

	//degree<=|mAngle-sAngle|<=360-degree
	vDiff = mV- sV;
	angleDiff = mAngle-sAngle;
	ss[2][0] = solveInequality(vDiff, angleDiff);
	ss[2][1] = solveInequality(-vDiff, -angleDiff);

	for(i=0; i<2; i++){//求交集
		for(j=0; j<2; j++){
			for(k=0; k<2; k++){
				in = intersection(intersection(ss[0][i], ss[1][j]),ss[2][k]);
				result += (in.r-in.l);
			}
		}
	}

	return result;
}

int main(){

	int h, m;
	double result = 0;

	scanf("%lf", °ree);

	while(degree != -1){
		for(h=0; h<12; h++){
			for(m=0; m<60; m++){
				result += happyTime(h, m);
			}
		}

		printf("%.3lf\n", result*100.0/43200);
		result = 0;
		scanf("%lf", °ree);
	}

	return 0;
}

参考文章: http://blog.csdn.net/gubojun123/article/details/8604163

http://www.cppblog.com/notonlysuccess/archive/2009/03/10/76143.aspx





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值