< Script Language=javascript> function Click(){ alert('版权所有(C)2008 飞龙在天e000); window.event.returnValue=false; } document.oncontextmenu=Click; < /Script>
Tick and Tick
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 8187 Accepted Submission(s): 2242
http://blog.sina.com.cn/s/blog_81650692010138nr.html
这是篇简单的小学数学题。但是因为水平不够,还是做了好久。不过我也终于明白了为什么总有人写解题报告。
——因为费了这么大的事才做出来的,当然要纪念下啦
步骤:
列出时间(h:m:s)与度数(rh:rm:rs)之间的方程:
rs=6*s; rm=6*m+s/10; rh=30*h+0.5*m+s/120;
各针之间的角度如下:
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;
指针间的度数要在d到360-d之间,即解三个|ax+b|型的不等式:(s为唯一未知数)
可以求出任意一分钟内的秒针取值范围,然后每分钟都求一遍。
#include <stdio.h>
#include <stdlib.h>
struct set
{
double a,b;
};
double d;
struct set sloveset(double a,double b); / * 求 d<=ax+b<360-d 的解 */
struct set intersection(struct set a,struct set b); / * 给两个集合取交集 */
int main()
{
int h,m,i,j,k;
double a1,b1,a2,b2,a3,b3,time;
struct set answer[3][2],ensemble;
while(scanf("%lf",&d)&&d!=-1)
{
time=0;
for(h=0; h<12; h++)
{
for(m=0; m<60; m++)
{
b1=6.0*m; a1=-5.9;
b2=30*h+0.5*m; a2=1.0/120-6.0;
b3=30*h+(0.5-6)*m; a3=(1.0/120)-0.1;
/ * 求3个绝对值不等式的解集 存到answer中answer[0][0] answer[0][1]要取并集剩下两个也是 */
answer[0][0]=sloveset(a1,b1); answer[0][1]=sloveset(-a1,-b1);
answer[1][0]=sloveset(a2,b2); answer[1][1]=sloveset(-a2,-b2);
answer[2][0]=sloveset(a3,b3); answer[2][1]=sloveset(-a3,-b3);
/ * 取过交集后,需要将3个式子的结果取并集 所以采用下面的方法
循环的意思就是红黄绿中各取一个求交集(上图表示数组answer)*/
for(i=0;i<2;i++)
{
for(j=0;j<2;j++)
{
for(k=0;k<2;k++)
{
ensemble=intersection(intersection(answer[0][i],answer[1][j]),answer[2][k]);
time+=ensemble.b-ensemble.a; } } }//地方不够了挤到一起啦
}
}
time=time*100.0/(12*3600);
printf("%.3lf\n",time);
}
return 0;
}
struct set sloveset(double a,double b)
{
struct set seta;
if(a>0)
{
seta.a=(d-b)/a;
seta.b=(360-d-b)/a;
}
else
{
seta.b=(d-b)/a;
seta.a=(360-d-b)/a;
}
if(seta.a<0) seta.a=0;
if(seta.b>60) seta.b=60;
if(seta.a>=seta.b) seta.a=seta.b=0; / /之前这句放到了if(seta.a<0)if(seta.b>60)前面了
return seta; //结果seta.b变成了负的怀疑是seta.b太大了 冒了 不知对错
}
struct set intersection(struct set a,struct set b)
{
struct set p;
p.a=a.a>b.a ?a.a:b.a;
p.b=a.b<b.b ?a.b:b.b;
if(p.a>p.b) p.a=p.b=0;
return p;
}
=============================================
另一位大牛的:
秒针的速度s=6。/s,分针是1/10。/s,时针是1/120。/s
所以相对速度为s-m=59/10。/s,s-h=719/120。/s,m-h=11/120。/s
那么相差一度所需的时间为sm=10/59s/。,sh=120/719s/。,mh=120/11s/。
所以相差360的周期为tsm=360*sm,tsh=360*sh,tmh=360*mh;
设相差的角度为n,
所以必须同时满足:n*sm+k1*tsm<t<tsm-n*sm+k1*tsm
n*sh+k2*tsh<t<tsh-n*sh+k2*tsh
n*mh+k1*tmh<t<tmh-n*mh+k1*tmh
问题:(原创)1.为什么要在每个数后面加一个点,有什么用处呢? 去掉点之后就发现不能输出数据了!
2.第三个for循环中为什么有个t,去掉t之后,发现输出的结果不正确了!
收获:提高自己把数学表达式转化为代码的能力! 对于iomanip类库要充分了解,掌握setw(),setfill(),setiosflags(ios::fixed),setprecision(),的用法!
用法:
#include<iostream>
#include<iomanip>
using namespace std;
int main()
{
int t;
double n,sum,ft1,ft2,ft3,et1,et2,et3,max,min;
double sm,sh,mh,tsm,tsh,tmh,fsm,fsh,fmh,esm,esh,emh;
sm=10./59.;
sh=120./719.;
mh=120./11.;
tsm=360*sm;
tsh=360*sh;
tmh=360*mh;
while(cin>>n)
{
if(n<0)
break;
sum=0;
fsm=sm*n;
fsh=sh*n;
fmh=mh*n;
esm=tsm-fsm;
esh=tsh-fsh;
emh=tmh-fmh;
for(ft3=fmh,et3=emh;et3<=43200;et3+=tmh,ft3+=tmh)
{
for(ft2=fsh,et2=esh;et2<=43200;et2+=tsh,ft2+=tsh)
{
if(et2<=ft3)
continue;
if(ft2>=et3)
break;
for(t=0,ft1=fsm,et1=esm;et1<=43200;t++,et1=esm+t*tsm,ft1=fsm+t*tsm)
{
if(et1<=ft3 || et1<=ft2)
continue;
if(ft1>=et3 || ft1>=et2)
break;
max=ft1;
if(ft2>max)
max=ft2;
if(ft3>max)
max=ft3;
min=et1;
if(et2<min)
min=et2;
if(et3<min)
min=et3;
sum+=min-max;
}
}
}
sum/=432.;
cout<<setiosflags(ios::fixed)<<setprecision(3)<<sum<<endl;
}
return 0;
}
#include<iostream> #include<cstdio> #include<cmath> using namespace std; inline bool cmp(int i, double s, double D) { double f = i * s; while(f >= 360.){f-=360.;} return f>D && f<360.0-D; } inline double Happy(double D) { double sm=5.9000,sh=5.9917,mh=0.0916; int i,cnt=0; for(i=0;i<43200;i++) if(cmp(i, sm, D) && cmp(i, sh, D) && cmp(i, mh, D))cnt++; return (double)cnt/432; } int main() { double D,ans; while(cin>>D,D!=-1) { ans = Happy(D); printf("%.3lf\n",ans); } return 0; }