プログラムの実行結果は以下の通り。
39回進み,5歩目,25歩目で逆向きに進む。詳細は以下の通り。 1 sum:1 2 sum:3 3 sum:6 4 sum:10 * 5 sum:5 6 sum:11 7 sum:18 8 sum:26 9 sum:35 10 sum:45 11 sum:56 12 sum:68 13 sum:81 14 sum:95 15 sum:110 16 sum:126 17 sum:143 18 sum:161 19 sum:180 180 OK 20 sum:200 21 sum:221 22 sum:243 23 sum:266 24 sum:290 * 25 sum:265 26 sum:291 27 sum:318 28 sum:346 29 sum:375 30 sum:405 31 sum:436 32 sum:468 33 sum:501 34 sum:535 35 sum:570 36 sum:606 37 sum:643 38 sum:681 39 sum:720 360 OK
プログラムのソースは以下の通り。
#include "puzutl.h"
const int N = 100; // まあこれくらいの数字の中に見つかるでしょ。
int sum[1+N] = {0}; // 事前に歩数の合計値は計算しておく
YesNo check180( int n, int i, int j) // ちょうど180度で止まるか?
// n :I:1歩,2歩,…,n歩進む
// i :I:この歩数の時逆方向に進む
// j :I:この歩数の時逆方向に進む
{
int sum = 0; // 進んだ歩数
for( int k=1; k<= n; k++) { // 1歩からn歩進む
if( k == i || k == j) sum -= k; // i,jで逆向きに進む
else sum += k; // i,j以外は時計回りに進む
if( (sum+180) % 360 == 0) { // sum%180にしてしまうと360度の場合も含まれてしまうので
return YES; // ちょうど180度で停止した
}
}
return NO; // 180度で停止することはなかった。
}
int main( int argc, cstring argv[])
{
int minn = 0; // 最低360度回転しなければならないので必ず進む歩数があるはず
for( int i=1; i<= N; i++) { // 最初にトータルの歩数を求めておく
sum[i] += i+sum[i-1]; // トータルの歩数は前の歩数に次の歩数を足したもの
if( minn == 0 && sum[i] > 360) { // 最低1周する所から調べ始める
minn = i; // minnを使わないで1から調べた方がバグが少ないプログラムになる
}
}
for( int n=minn; n< N; n++) { // 合計数字が針の動く回数だから小さい数字から調べていく
for( i=1; i< n; i++) { // その中から2つの数字を選択して調べる(一つめの数字)
for( int j=i+1; j< n; j++) { // もう一つの数字(一つめより必ず大きな数字)
int back = i+j; // 2つの数字の合計
if( ((sum[n]-back-back)%360) == 0) { // 2回引き算するのは,回ったと仮定してある分を取り消し,更にその分元に戻る
if( check180( n, i, j)) { // その中にちょうど180で止まっているものがあるか?
ps( "%d回進み,%d歩目,%d歩目で逆向きに進む。詳細は以下の通り。\n", n, i, j);
int sum = 0; // 以下詳細の出力
for( int p=1; p<= n; p++) {
if( p == i || p == j) sum -= p;
else sum += p;
ps( "%s %d sum:%d", (p==i||p==j)?"*":" ", p, sum);
if( (sum+180)%360 == 0) ps( " 180 OK"); // sum%180にしてしまうと360度の場合も含まれてしまうので
if( sum%360 == 0) ps( " 360 OK");
ps( "\n");
}
return 0; // 答えが見つかったので終了
}
}
}
}
}
pe( "答えが見つからない\n");
return 0;
}