时钟问题VS解不等式求交集

Tick and Tick

 

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 7884    Accepted Submission(s): 2177

 

 

Problem Description

The three hands of the clock are rotating every second and meeting each other many times everyday. Finally, they get bored of this and each of them would like to stay away from the other two. A hand is happy if it is at least D degrees from any of the rest. You are to calculate how much time in a day that all the hands are happy.

 

 

Input

The input contains many test cases. Each of them has a single line with a real number D between 0 and 120, inclusively. The input is terminated with a D of -1.

 

 

Output

For each D, print in a single line the percentage of time in a day that all of the hands are happy, accurate up to 3 decimal places.

 

 

Sample Input

 

0 120 90 -1

 

 

Sample Output

 

100.000 0.000 6.251

 

 

Author

PAN, Minghao

 

 

Source

ZJCPC2004

 

 

Recommend

JGShining

 

解:上次接触时钟问题是一道面试智力题,问的是时针分针一天之内相遇多少次(22次).今天在HDU上看到这道题,应该是第6道,菜鸟做ACM,压力大啊.

先上网搜一下有关时钟问题的解释特点原理之类的.如下:

http://wenku.baidu.com/view/7fd92105e87101f69e31959a.html

http://baike.baidu.com/view/1389109.htm

http://www.cnblogs.com/doubleming/archive/2012/10/17/2727502.html

简略地看了看上面的资料,有点多,反而有些一叶障目,不见泰山的感觉,不过没有关系,至少还是有一些了解的.为了更感性地认识时钟问题,我们先来个钟,如下所示

时钟问题VS解不等式求交集_第1张图片

 

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

钟表上有60小格,所以每一小格是360/60=6度.

秒针1秒走1小格,所以秒针的速度是6 度/秒

分针1分钟走1小格,所以分针的速度是6/60=1/10 度/秒.

时针1小时走5格,所以时针的速度是5*6/60*60 = 1/120度/秒

 

我们要找happy time.即时分秒针的每两两的夹角需要大于所给出的degree.数学上如何描述?

为了理解这个问题,我们可以先引入偏转角的概念:针与12刻度线顺时针方向的夹角称为偏转角.

时针,分针,秒针的偏转角分别记为h_angle,m_angle和s_angle.

假定当时时间是:h时m分s秒.则有

h_angle = 1/120 * (h*60*60+m*60+s) = 30h + m/2 + s/120 ......(1)

m_angle= 1/10 * (m*60+s) = 6m+s/10.......................................(2)

s_angle = 6s..............................................................................(3)

 

我们想要happy(时针,分针,秒针偏转角之差大于degree而且小于360-degree,为什么?

因为如果大于360-degree,则会在另一头导致夹角之差小于degree),则需要满足下列不等式:

 

degree<|h_angle - m_angle|<360-degree

degree<|h_angle - s_angle|<360-degree

degree<|m_angle - s_angle|<360-degree

 

将(1).(2).(3)式代入上面.有

 

degree<|(1/120.0 - 1 /10)s +(30h + m /2 - 6m)|<360-degree .......(4)

degree<|(1/120 - 6)s+( 30h + m /2)|<360-degree.........................(5)

degree<|(6.0 - 0.1)s +(-1*m*6.0)|<360-degree.............................(6)

 

至此,上面的一切都只是数学推导,上式的||内都有一个共同的特征a*s+b,

其中a是常数,b可能包含,h,m.我们可以将h,m都看作常数,解上述的3个关于s的不

等式(4)(5)(6)根据绝对值符号内的正负可以分为两个不等式.可以解得两个区间.

(这两个区间是地位等同的),例如2<|x|<5可以解出,-5

分别解出每个式子的区间以后,再对(4)(5)(6)的区间做交集运算.就可以解得s的happy区间,

区间长度即为这一分钟所求的happy时间.

所以,归根结底:这道题的关键是:

1.解形如low <|ax+b|

2.求3个连续集合的交集.

上面的算法可以实现求某一分钟内,秒针的happy时间,因此,可以用一个二层循环遍历从h到m的每一分钟,

再调用这个子函数,就可以得出结果,不得不承认,这种穷举法不是很优雅.

具体从代码中体会:

#include
struct Range //happy time区间(s)
{
	double low; //单位是秒
	double high;
};
//解不等式: low < |as+b|  0)
	{
		R.low = (low-b)/a ;
		R.high = (up - b)/a;
	}
	else if( a < 0 )
	{
		R.low = (up - b)/a;
		R.high = (low - b)/a;
	}
	if( R.low < 0) R.low = 0 ; //R的区间取值范围是[0,60],单位秒
	if( R.high > 60) R.high = 60 ;
	if( R.low >= R.high ) R.low = R.high = 0 ;
	return R ;
}
// 求最三个数的大值
double Max(double a,double b,double c)
{
	double Temp = a > b ? a : b ;
	return Temp > c ? Temp : c ;
}
//求三个数的最小值
double Min(double a,double b,double c)
{
	double Temp = a < b ? a : b ;
	return Temp < c ? Temp : c ;
}
//求三个区间的交集
Range Intersection(const Range& a,const Range& b,const Range& c)
{
	Range R;
	R.low = Max(a.low , b.low , c.low ) ;
	R.high = Min(a.high , b.high , c.high ) ;//一开始笔误写成a.high,b.high,b.high,太悲剧了
	if( R.low >= R.high )
		R.low=R.high=0 ;
	return R;
}

double HappyTime(double h,double m,double low ,double up)
{
	Range R[3][2];
	double a,b;
	a = 1/120.0-1/10.0;
	b = h * 30.0 + m /2.0 - m * 6.0;
	//求绝对值不等式l<|a|


 

 

 

你可能感兴趣的:(算法分析与设计,C++,acm)