Hang Dian oj 1006 Tick andTick個人的な問題の解決策
まず、公式サイトに元の質問を掲載しましたが、
最初はこの質問を見て、また水に関する質問だと思いましたが、よく見てみると、もっと数学のテストだと気づき、本当に長い間苦労しました。これが私の考えのいくつかです:
アイデア1:暴力シミュレーション方法
おそらくほとんどの人は秒を使って時計をシミュレートし、秒数に応じて時針と分針の位置を決定し、時間を累積します。ここでは、1秒、0.1秒、0.01秒、さらには0.001秒を単位時間シミュレーションとして使用できますが、実際には2つの大きな欠点:
1。単位時間が短く、シミュレーションの数が多い。
2.精度が十分でない場合は、小数点以下3桁を維持してください。
シミュレートするのに秒を使用していませんが、秒針が移動した度を使用してシミュレートしているため、時間と度の変換を節約できます。
知っておく必要があるのは、秒針の速度= 60×分針の速度= 720×時針の速度
です。これが私が書いたコードです(最初のアイデアとして提出され、ojで失敗しました)。
#include<bits/stdc++.h>//这个头文件也称万能头,包括c和c++的很多头文件
using namespace std;
int main()
{
int n;
double a=0,t=0,miao,fen,shi;
cin>>n;
while(n<=120&&n>=0)
{
//模拟时钟
while(shi<360)
{
t+=0.45;//t是计算总时间,以0.45°为单位累加
miao=t-(int)t/360*360;//这里因为t为double型,用不了%,所以自己写了一个类似与%的东西。
fen=t/60-(int)t/60/360*360;
shi=t/720;
if(abs(miao-fen)>=n&&miao-fen+360>=n&&fen+360-miao>=n)//这里的判断略显繁琐,其实可以用define宏来简化代码。
if(abs(miao-shi)>=n&&miao-shi+360>=n&&shi+360-miao>=n)
if(abs(fen-shi)>=n&&fen-shi+360>=n&&shi+360-fen>=n)
a+=0.45;//a用来统计开心时间
}
printf("%.3lf\n",a/t*100);//c++的小数点控制不大会用,方便起见用了c的printf函数
cin>>n;
a=t=shi=0;//这里需要重置数据
}
cin.get();
cin.get();//这里用两个cin.get();来暂停界面,保留窗口,不影响oj的判断
}
実際には、処理プロセスの詳細は次のように多くあります。
たとえば、abs(miao-fen)> = nのように3つのifが記述され、miaoとfenの程度の違いを判断します。ここでは、fenの程度が可能であるため、absが使用されます。 miao以上(開始位置に対して)。また、次の(miao-fen + 360)> = nおよびfen-miao + 360は、別の角度を計算するために使用されます。
その後、この0.45を何度かデバッグしました。最初は0.01を使用しました。実行後、実行時間が長すぎることがわかったので、大きい値に変更して1にしました。テストサンプルは正しかったのですが、提出時に提出しました。間違っています(十分な精度がありません)。
提出された写真を貼り付け
ます。ここに間違った答えが表示され、実行時間も短くありません。
だから私は時間を正確さと交換しようとした。
結果は図のようになります。
次に、0.5に増やしてみます:減らします
(心が疲れます)、0.45:
ojが拒否する適切なアルゴリズムがないことがわかります!
そこでBaiduを始めて、他の多くのブロガーが方程式を解く形式を使用していることに気づきましたが、全員がコードを投稿していました。理解できなかったか、読むのに長すぎました。あきらめたかったのですが、後で考えました。そうしないと絶対に起こらないので、もう一度やり直したほうがいいです。
今日一日中過ごした後、私はついにノックアウトしました。それがアイデア2です。
アイデア2:方程式を解き、条件を満たす2つの間の間隔を計算し、最後に交点を取り、間隔をマージします。
チャット:
私の苦労全体について話させてください(ブロガーの個人的なナンセンスである、見たくない場合はスキップできます):
最初に、数学の問題を使用するというアイデアについて考えました、つまり、最初に分針と時針にnクリップを生成させます角度を付け、この時点で時間を計算し、これに基づいて秒針の位置を決定します。これが途中で諦めたコードです。
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n,q=0;
double miao=0,fen,shi,t1,t2,t3,t4,ans=0;
cin>>n;
while(n<=120&&n>=0)
{
//解多次方程
while(720/11*(n+q*360)<259200)//用度数来解方程
{
t1=720/11*(n+q*360);q++;//解出分针与时针满足条件时的时间
t2=720/11*(q*360-n);//t1,t2用来确定分针和时针开心的边界,t3,t4用来确定秒针分别与时针和分针的开心边界
//用for循环寻找在t1-t2该区间的miao的范围
t3=t4=0;
for(int i=0;t3<259200;i++)
{
t3=(n+(i*360))*720/719;
if(t1<t3&&t3<t2)break;
}
for(int i=0;t4<259200;i++)
{
t4=(360*(i+1)-n)*720/719;
}
}
}
cin.get();
cin.get();
}
しかし、後で私はそれが間違っていることに気付きました。T3とt4は前にあり、後ろには何がありますか?T3とt4は公開部分に移動する必要があり、最後のt3または最後のt4の時間などと重複する可能性があり
ます。すべての問題を解決するために大量のデータを保存できる
正题:
実際、この質問を振り返ると、彼が私たちに求めたのは、条件を満たすすべての時間間隔を計算し、それらを加算して、最後に合計時間の割合を計算することであることがわかります。
1日24時間の最初の12時間と最後の12時間だからです。時間の状況は同じなので、合計時間として12時間を使用します。
まず、この質問の一般的なフレームワークは、条件を直接満たす間隔を計算することです(3つの条件すべてを一度に満たすことはできません)。計算)
つまり、時針と秒針の間隔、時針と分針の間隔、分針と時針の間隔で、最後に交差点を取得します。
最初にコードを貼り付けてから、次のように説明します。
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n,s1=0,s2=0,s3=0,s4=0;
double ms[2000],fs[30],fm[2000],h1[2000],ans=0;
cin>>n;
while(n<=120&&n>=0)
{
for(int i=0;(n+360*i)*720.0/719<259200;i++)
{
ms[s1++]=(n+360*i)*720.0/719;
ms[s1++]=((i+1)*360-n)*720.0/719;
}
for(int i=0;(n+360*i)*720.0/11<259200;i++)
{
fs[s2++]=(n+360*i)*720.0/11;
fs[s2++]=((i+1)*360-n)*720.0/11;
}
for(int i=0;(n+360*i)*60.0/59<259200;i++)
{
fm[s3++]=(n+360*i)*60.0/59;
fm[s3++]=((i+1)*360-n)*60.0/59;
}
//合并fs和fm,并入h1之中
for(int i=0;i<s2;i+=2)
for(int j=0;j<s3&&fm[j]<fs[i+1];j+=2)
{
if(fm[j+1]>fs[i])
{
h1[s4++]=max(fm[j],fs[i]);
h1[s4++]=min(fm[j+1],fs[i+1]);
}
}
//合并h1和ms,并入fm
s3=0;
for(int i=0;i<s4;i+=2)
for(int j=0;j<s1&&ms[j]<h1[i+1];j+=2)
{
if(ms[j+1]>h1[i])
{
fm[s3++]=max(ms[j],h1[i]);
fm[s3++]=min(ms[j+1],h1[i+1]);
}
}
for(int i=0;i<s3;i+=2)ans+=fm[i+1]-fm[i];
printf("%.3f\n",ans/259200*100);
s1=s2=s3=s4=ans=0;
cin>>n;
}
cin.get();
cin.get();
}
1.1。
intタイプ:
nは入力データを格納するために使用されます
s1はms配列の要素数を格納するために使用されます(1440、保険目的で2000を使用)
s2はfs配列内の要素数を格納します(
24、30を使用)s3はfm配列を格納します(推定1440、2000を使用)
s4の要素数は、h1配列の要素数(推定1440、2000を使用)を格納します。
2.2。
ダブルアレイ:
msアレイは、秒針と時針が条件を満たす間隔(msは秒の省略形)
など
を格納します。h1アレイは、最初のマージの間隔を格納するために使用されます(2 x 2マージは2回、元々は2つあるはずです)。配列はマージ間隔を格納するために使用されますが、最初にfsとfmをマージしたため、fm配列は2回目のマージでは役に立たず、最後の間隔配列として空にすることができます。さらに、fs配列の値は非常に少ないため、最初にマージします。 fs配列は数倍少なくループすることができます)
doubleansは幸せな時間を保存するために使用されます。
3.(コア部分)
それを計算する方法は方程式を解く方法ですか?
実際には非常に単純です。例として、秒針と時針のn = 90°を取り上げます。ここでは、次数シーケンスの式を使用します。つまり、秒針の次数をxに設定すると、最初に条件が満たされます
。xx/ 720 = 90
の秒針が時針をもう1円超えた場合はどうなりますか?
xx / 720 = 90 + 360
別の円はどうですか?
xx / 720 = 90 + 360×2
…
xx / 720 = 90 + 360×i
この場合、解はx =(90 + 360 ×i)×720/719。
実際に
は、時針と秒針という別の状況があります。
秒針が時針を超えて時針を追いかけると、最初に条件が満たされたとき:
x / 720 + 360-x = 90、
iサークルの後も同じことが言えます:
x / 720 + 360×ix = 90
はx =(360×i-90)×720/719に解決されます。
次に、秒針と分針、分針と時針を同じように類推することができます。
最後に、2つずつ組み合わせて時間と時間を累積します。次の計算のために比率を出力した後、データをリセットすることを忘れないでください。
(追記:ブロガーをサポートするコメント、深夜12時30分、少し眠いです〜)
下書きを添付してください(ランダムなもの)