例の算数の問題を不真面目に解いてみた
閉じる
閉じる

新しい記事を投稿しました。シェアして読者に伝えましょう

×

例の算数の問題を不真面目に解いてみた

2015-05-26 02:01
    毎度どうも(´・ω・`)きるひです.

    少し前に動画を見ていたら
    http://ch.nicovideo.jp/gizmodo/blomaga/ar796473?ref=zero_marq&ver=video_q
    http://www.theguardian.com/science/alexs-adventures-in-numberland/2015/may/21/how-to-solve-the-maths-puzzle-for-vietnamese-eight-year-olds-that-stumped-parents-and-teachers
    こんなものが目に入ったわけですが・・・
    解こうと思ったけどめんどくさかったので適当に解いて(解かして?)みました(´・ω・`)

    というわけで まずは問題.

    こんな感じになってます.この空白には1~9の数字が入ります.

    これをまっすぐな数式になおすと,
    □+13×□/□+□+12×□-□-11+□×□/□-10=66
    となります.
    まあ,真面目に考えてもいいわけなんですが・・・,解説は載ってるので
    ここはC言語を使ってPCに解いてもらいましょう.

    というわけで上記の数式を配列x[9]に置き換えてCの数式の形で記述すると
    x[0]+13*x[1]/x[2]+x[3]+12*x[4]-x[5]-11+x[6]*x[7]/x[8]-10=66

    さて,ここに1~9を順番に入れていって答えが66になるものを見つければ良いですが
    通り数が多いのでとりあえず並び替えのプログラムを書くのがめんどくさい.
    というわけで,今回はとりあえず幾つか解がわかればいいやってことで,
    x[0]~x[8]に1~9の乱数を適当に発生させて後はPCにパワープレイで解かさせることに.

    こんなかんじにプログラムの仕様が決まったので,アルゴリズムを書いてみると,
    1,1~9の乱数を発生させる,この時に数字のかぶりが無いようにする
      (そのためのチェック部分を作る)
    2,数式に代入してその数値だった時の答えを求める
    3,条件を満たしたか確認する.
      正しい解が求められていたらループから離脱,駄目だったら繰り返し
    4,ループから離脱したら,結果を表示する.

    のようになります.並び替え書くよりも多分簡単っすね(´・ω・`)

    ここで,使用する数字を考えてみると,幾つか対策をしないといけない部分が出てきます.
    この数式には割り算が出てきますが,C言語の場合,数字を整数にしてしまうと,
    割り算時に小数部分が消えてしまいます.

    そこで,乱数は整数で発生させる一方で,計算は浮動小数点数で計算させることにします.
    よって,x[9]は浮動小数点数とし,乱数は発生時にキャストさせて代入します.
    これで66が正しく出てくる・・・ とおもいきや

    割り算で小数が出てきた後足すと小数部分が消える場合があるので,
    それを確認させる必要があります.これは条件判断のところに追加してやれば良いです.
    この判断は,先ほどの整数にすると小数が消えることを利用すれば良いので,
    (割り算がある項)-(割り算がある項を整数にキャスト)=0
    のとき求めたい解であると考えてみたり.

    ・・・で
    実際に解いてみると,なんだか答えが複数あるようなので,これを更にループでおいて
    適当に幾つか解を出させるために,更にループで囲って100回くらい計算させることに.

    さて,書いたプログラムを以下に張ってみます.(クソプログラムでも勘弁(´・ω・`))
    試してみたい方は適当にコピーして使ってください.
    (なおエラー吐いても対応出来ないのでご了承ください)
    ===========================================

    #include <stdio.h>
    #include <stdlib.h>

    int main(void)
    {
    double x[9];
    int i,j,k;
    double ans;
    int check=0;

    k=0;

    while(1)
    {
    while(1)
    {
    //乱数挿入(1~9)
    for(i=0;i<9;i++)
    {
    while(1)
    {
    x[i]=((double)(rand() % 9) + 1.); //x[i]の乱数を発生させる

    for(j=0;j<i;j++) //かぶっちゃや~よ
    {
    if(x[i]==x[j])
    check++;
    }

    if(check>=1) //かぶったかどうかチェック
    {
    check=0;
    continue;
    }
    //無事にかぶらなかったら次の乱数発生に進む
    else
    break;
    }

    }

    //数式チェック
    ans=x[0]+13.*x[1]/x[2]+x[3]+12.*x[4]-x[5]-11.+x[6]*x[7]/x[8]-10.;

    if(ans==66. && (13.*x[1]/x[2])-((int)(13.*x[1]/x[2]))==0 && (x[6]*x[7]/x[8])-((int)(x[6]*x[7]/x[8]))==0)
    break; //解が66になる かつ 割り算を含む項が個別に小数部分を持たないとき条件を満たす

    else
    continue; //駄目だったらもう一回行ってみよ~
    }

    //解の表示
    printf("%2.4lf ",ans); //まず一応66が解であることを表示
    ans=0;

    for(i=0;i<9;i++)
    printf(" %2.2lf, ",x[i]); //それぞれの値を表示

    printf("\n"); //表示し終わったら改行して見やすく

    //繰り返しループ判定
    if(k>100)
    break; //100回くらい繰り返しましょうね~

    else
    {
    k++; //100回に満たなかったらもう一回行ってみよ~
    continue;
    }
    }
    return 0;
    }

    ===========================================

    これによって次のような結果が得ることが出来ます.

    これを見ると,確かに元の問題の解説にある
    3 2 1 5 4 7 9 8 6 の順も,求められています.

    まあこんなかんじでいいんじゃないかなぁと謎の自己満足(ぉ
    というわけで今回は以上です.
    プログラムはご自由に使用してください.(煮るなり焼くなり課題に使うなり)
    なお何があってもクレーム等は受け付けませんので
    それだけ注意でよろしくお願いします(´・ω・`)
    広告
    コメントを書く
    コメントをするには、
    ログインして下さい。