HDU1006
这是我的问题HDU在第一的第二手表遇到的问题,他们是非常具有欺骗性!
首先。我想大家都出问题理解。
实上吧,我认为这题HDU的思想有问题。钟表是一秒一秒走的,哪有连续时间。表示不解!
但题目要求,木有办法了。其次呢,结果要求保留三位有效数字。
这也就直接导致了:假设离散的来记录满足条件的时间的话,会在精度上出错!
如今,来分析下我对这题的做法吧。
题目要求一天(24小时)各个指针的happy time。
那么我们该怎么看各个指针呢?最好还是让刚開始时各个指针都指在12点的位置,12小时之后又会再回到12点位置,再反复一遍,就可以获得24小时总的happy time。显然,记下前12小时的就可以啦。
边贴代码边分析吧。
①离散计时(即一秒一秒的计时),结果输入90,输出6.225。
(个人觉得这样的方法没错。)
#include<iostream> #include<iomanip> using namespace std; double calculate(double a,double b) { double temp=(a-b)>0?(a-b):(b-a); return temp>(360.0-temp)?(360.0-temp):temp; } int main() { double degree,flag; const double h_degree=360/(12*60*60.0),m_degree=360/(60*60.0),s_degree=360/60.0; unsigned int rem_h=1,rem_m=1,rem_s=1,count=0; while(cin>>degree && degree>=0.0) { while(rem_h<=12*60*60) { if( calculate(rem_h*h_degree,rem_m*m_degree)>=degree ) if( calculate(rem_m*m_degree,rem_s*s_degree)>=degree ) if( calculate(rem_h*h_degree,rem_s*s_degree)>=degree ) count++; rem_h++; rem_m++; rem_s++; if(rem_s==60+1) rem_s=1; if(rem_m==60*60+1) rem_m=1; } flag=count/(12*60*60.0)*100.0; cout<<setiosflags(ios::fixed); cout<<setprecision(3); cout<<flag<<endl; rem_h=rem_m=rem_s=1; count=0; } return 0; }
②苦于AC无门。也仅仅能找网上大牛们的成品了!
(菜鸟的无奈)
⑴但第一遍依然是TLE了,后来明确了能够优化。
#include<iostream> #include<iomanip> using namespace std; //const double w_h=1.0/120,w_m=1./10,w_s=6.0; //角速度 const double hm=11.0/120,hs=719.0/120,sm=59.0/10; //相对角速度 const double T_hm=43200.0/11,T_hs=43200.0/719,T_sm=3600.0/59; //相对周期 inline double min(double a,double b,double c) { double temp=(a>b)?b:a; return (c>temp)?temp:c; } inline double max(double a,double b,double c) { double temp=(a>b)?a:b; return (c>temp)?c:temp; } int main() { double degree; double x[3],y[3]; double m[3],n[3]; double end,begin,sum; while(cin>>degree , degree!=-1) { x[0]=degree/hm; x[1]=degree/hs; x[2]=degree/sm; y[0]=(360-degree)/hm; y[1]=(360-degree)/hs; y[2]=(360-degree)/sm; sum=0.0; for(m[0]=x[0],n[0]=y[0];n[0]<=43200.000001;m[0]+=T_hm,n[0]+=T_hm) { for(m[1]=x[1],n[1]=y[1];n[1]<=43200.000001;m[1]+=T_hs,n[1]+=T_hs) { for(m[2]=x[2],n[2]=y[2];n[2]<=43200.000001;m[2]+=T_sm,n[2]+=T_sm) { begin=max(m[0],m[1],m[2]); end=min(n[0],n[1],n[2]); if(end>begin) sum+=end-begin; } } } cout<<setiosflags(ios::fixed)<<setprecision(3)<<sum*100.0/43200<<endl; } return 0; }
⑵AC代码。也用了578MS。险过呀!
分析下AC代码的思想。
因为要记录连续时间。那么就利用区间记录。[begin,end]。
另外,就拿时针和分针来做样例吧。
时针的角速度为w_h=360.0/12*60*60=1.0/120。分针的角速度为w_m=360.0/60*60=1.0/10。两者的相对角速度为w_hm=w_m-w_h,“相对周期”为T_hm=360.0/w_hm。所谓的相对周期就是时针和分针出现反复的相对关系的最小时间。
这种话就能够把时针和分针,时针和秒针,分针和秒针各自满足条件的集合求交集。显然。代码中利用的是三个for循环来暴力解决。只是有些显然不满足条件的情况就可以去除,以降低计算次数。
x[3]和y[3]记录的是第一个開始满足条件的时间和第一个開始不满足条件的时间。m[3],n[3]则是分表依据相对周期来扩大x[3],y[3]以获得全部满足条件的时间集合。并求交集。
#include<iostream> #include<iomanip> using namespace std; //const double w_h=1.0/120,w_m=1./10,w_s=6.0; //角速度 const double hm=11.0/120,hs=719.0/120,sm=59.0/10; //相对角速度 const double T_hm=43200.0/11,T_hs=43200.0/719,T_sm=3600.0/59; //相对周期 inline double min(double a,double b,double c) { double temp=(a>b)?b:a; return (c>temp)?temp:c; } inline double max(double a,double b,double c) { double temp=(a>b)?a:b; return (c>temp)?c:temp; } int main() { double degree; double x[3],y[3]; double m[3],n[3]; double end,begin,sum; while(cin>>degree , degree!=-1) { x[0]=degree/hm; x[1]=degree/hs; x[2]=degree/sm; y[0]=(360-degree)/hm; y[1]=(360-degree)/hs; y[2]=(360-degree)/sm; sum=0.0; for(m[0]=x[0],n[0]=y[0];n[0]<=43200.000001;m[0]+=T_hm,n[0]+=T_hm) { for(m[1]=x[1],n[1]=y[1];n[1]<=43200.000001;m[1]+=T_hs,n[1]+=T_hs) { if(n[0]<m[1]) break; if(m[0]>n[1]) continue; for(m[2]=x[2],n[2]=y[2];n[2]<=43200.000001;m[2]+=T_sm,n[2]+=T_sm) { if(n[0]<m[2] || n[1]<m[2]) break; if(m[0]>n[2] || m[1]>n[2]) continue; begin=max(m[0],m[1],m[2]); end=min(n[0],n[1],n[2]); if(end>begin) sum+=end-begin; } } } cout<<setiosflags(ios::fixed)<<setprecision(3)<<sum*100.0/43200<<endl; } return 0; }
欢迎拍砖!