• ベストアンサー

数独(ナンプレ)の解き方(アルゴリズム)

プログラミングの宿題で、Javaを使って数独を解くプログラムを作っています。雑誌などにある数独の問題を解くことはできたのですが、今回はその問題もプログラムで作ってそれを解かせようというお題になってしまいました。今のところ下のような感じになっています。 1. 乱数を使って0-80までのマス番号に1-9の数字を数個適当に入れていきます。(0が左上の角で、80が右下の角です。) 乱数でマスに数字を入れますから、同じマスに数字が入ることがありますが、それはそれでそのマスを上書きしています。さらにこの段階で、数字が同じ列または3×3マスで重なることがないようにしています。 2. それを元に各マスに入る可能性のある数字をリストアップ 3. リストアップした中で、最後に必ず1つだけ数字が残るのでそれをそのマスに入れます。 とここまではできました。しかし、乱数で適当に問題をつくったにしか過ぎないから、当然ダブってしまうところや、数字が入らないマスがあります。ですから、そういったダブるところや数字の入らないマスのために補正をしたいと思うのですが、まったくアイディアが浮かびません。どのようにしたら補正をして問題を回答できますか? アルゴリズムが少々長くてもかまいません。また、Javaのコードでの回答でなくてもかまいません。とにかく、如何の様に補正するのかを知りたいです。 下にあるのが、上の1.で作った問題です。 # 0は数字が入っていないマスを示します。 060 | 000 | 080 030 | 080 | 017 000 | 100 | 000 --------------- 800 | 000 | 903 000 | 803 | 060 000 | 096 | 500 --------------- 908 | 407 | 000 205 | 000 | 400 700 | 001 | 000

  • potch
  • お礼率52% (34/65)

質問者が選んだベストアンサー

  • ベストアンサー
  • pueplo
  • ベストアンサー率29% (11/37)
回答No.5

#1です。 スードコードって以外に難しいんですよね~ 本アレー をsu[a,b] ダメアレーをdoku[c,d,e] として。 { まずは抽選 suに入る数字を乱数より導く。 dokuアレーを使って検査 dokuアレーにその数字の記載があれば、ここでループを終えるか?もう一度再抽選(ループはじめに戻る!) もし、dokuアレーに乱数で引き出した数字が無ければ~ ポジションa,bを使って、数字が入るか?検査をする。 レツ検査su[a,*]  ココでボツなら、dokuアレーに代入&再抽選(ループはじめに戻る) OKなら レツ検査su[*,b] ココでボツなら、dokuアレーに代入&再抽選(ループはじめに戻る) OKなら コワクはちょっと難しいですが、switchなどを使ってみては? ポジション 0<=a<=2,0<=b<=2 3<=a<=5,0<=b<=2 6<=a<=8,0<=b<=2 0<=a<=2,3<=b<=5 ~ ~ ~ ~ ~ てなかんじでコワクをスイッチ回路で制限して 検証する。 もしコワクの中で数字を共有していれば、dokuアレーに数値を代入、再抽選 無ければ、それが当たりの数字!! オプション((レツのほかのdokuアレーとコワクの他の場所に当たりの数字を代入すれば、抽選効率は後々になると、早くなるはずです。)) } //コメント// dokuアレー9X9X9のアレーにしておいて、9個数字が埋まったら、そのパターンは廃棄!という回路を作っておいてもよさそうですね。 javaが専門ではないので、CとVBが混じっていますが、同じように出来るはずです。 頑張ってみてください!

potch
質問者

お礼

アルゴリズムの提供ありがとうございました。 なかなか、うまくアルゴリズムの再現ができなくて結局宿題の期限となんてしまいました。提供してもらったのに、申し訳ない気持ちでいっぱいです。

potch
質問者

補足

自分に技術力が無いばかりに本当に申し訳ないのですが、上のアルゴリズムを得意としている言語でかまわないので(でも、Basic以外だと助かります)、実際のコードに起こしてもらえませんか? 本当にすみません。 また、#4さんのアルゴリズムもコードに起こしてもらえると助かります。

その他の回答 (5)

  • laputart
  • ベストアンサー率34% (288/843)
回答No.6

VBで問題と解答のプログラムを作りました。5年以上前からパズル雑誌に掲載されていました。 考え方としては、 (1)まず解答を作成する(配列0から80まで数字が確定した) (2)これを元にヒント升を決定する (3)実際にPCに問題を解かせて最後まで出来るかどうか検証する という事が一番速いと思います。 まず(1)についてですが、 ◆どの数字2つ(例えば数字の1と9)を全て入替えても矛盾はしないという事 ◆列番号(0から8で)012を全て入替えても矛盾しないと いうこと ◆行も同様です。 ◆更にブロックの入替えも出来ます よって配列0から80までを乱数ではなくてシリアル値代入して矛盾ないように最後まで完成しても一般性を失わないという事です。 VB的な書方になりますが Dim A(80) as Integer (整数) Dim B(80) as String * 9 (文字列) B(0から80)に "123456789"を代入 <-どの数字が入ってもいいということ A(0から80)に0を代入 A(0)=1 b(0)="1********" <--- 数字1が確定 b(1から8)を "*23456789"にする (数字1が入らない) B(縦の列)、B(0)を含むブロックも同様にする A(1)=2を代入 (1は入らない) と同様の試行を続けていきます。 この方法なら乱数を使わずに問題を作成する事が可能です。 それと乱数の場合は途中で矛盾が発生した場合、何度も後戻りするので なかなか最後まで行かないのではないかと思います(まだ試した 事はありませんが)  

  • SortaNerd
  • ベストアンサー率43% (1185/2748)
回答No.4

{ 既出数字チェック用に9×9×9の配列を作る。 乱数でマスを選ぶ。第i行第j列とする。 乱数で数字を選ぶ。nとする。 [i,j,n]を見る。既にチェックがあったらやり直し。 チェックがなかったら第i行第j列の数字はnと決定し、その数字と、それによって置けなくなる数字にチェックをつける。 ここで置ける数字がただ一つに決まってしまったマスがあるならば、そのマスのその数字の部分にチェックをつける。そしてそれにより置けなくなる数字にもチェックをつける。 } をチェックが全部埋まっていない限り続ける。 といった感じでしょうか。ソースを人に伝えるのって難しいですね。

potch
質問者

お礼

アルゴリズムの提供ありがとうございました。 なかなか、うまくアルゴリズムの再現ができなくて結局宿題の期限となってしまいました。提供してもらったのに、申し訳ない気持ちでいっぱいです。

potch
質問者

補足

#1・#3さんへの補足もこちらでさせていただきます。 ということは上にあるソースの説明がバックトラック法で解く場合の方法ということでいいのでしょうか? (自分が解釈できた範囲で言えば、これじゃないかと思うのですが・・・)

  • rabbit_cat
  • ベストアンサー率40% (829/2062)
回答No.3

こういう問題は、基本的には、いかに枝刈りをして、可能性を少なくできるか、にアルゴリズムの良し悪しがかかっています。 一番、基本的な枝刈りの方法は、#1さんにでている、いわゆる「バックトラック」というやつです。 バックトラックでWeb検索すれば、たくさんページが見つかると思います。 バックトラックは、この枝は刈ってかまわない、ということをいかに早く見つけられるかで性能が決まります。 さらに高度な枝刈りとしては、バックトラック(深さ優先探索)に幅優先探索を組み合わせるとか、確率的なアルゴリズムを取り入れるとか、いろいろあります。

potch
質問者

お礼

アルゴリズムのヒントありがとうございました。 なかなか、うまくアルゴリズムの再現ができなくて結局宿題の期限となってしまいました。

  • age_momo
  • ベストアンサー率52% (327/622)
回答No.2

最近、Excel VBAで同様の解法プログラム作りました。 質問者さんの解法のプログラムは白紙の問題にも対応しているのでしょうか? もし、対応しているなら全て決めてからランダムに空白を作った方がいいと思うのですが。 また、ここで言う問題の定義ですが、普通、解答が一意的に決まるものを言っているでしょうか?何通りも解答があるのでは例えば空白でも問題と言えるわけで、少し適当でないように思いますが。(その場合は出来上がった答えから空白を作っていくときに解答が一通りかどうかチェックしながら抜いていく事になりますね。こちらは考えた事ないですが結構面倒そうです)

  • pueplo
  • ベストアンサー率29% (11/37)
回答No.1

絶対入らない!数字がありますよね。 例えば、コワク(3X3のセット)とレツ(1X9と9X1) この2つを乱数で入力した時に、チェックする検査をつくり、ボツが出れば、直前に入れたバリューを無効にする!という方法でどうでしょうか? アレーを作っているはずですから、簡単な分岐でこれらのチェックは簡単に出来るはずです。 もう少し高度になると、没リストアレーを製作(9X9X8の3Dアレー)ボツにした数字をコレクトしておいて、乱数で弾き出した数字が、ボツリストにあれば、再抽選する!なんて作っておけば、チョッピリ高速化?しません??? 参考まで。

関連するQ&A

  • javaで数独を解くプログラムについて

    java初心者です。 学校で数独を解けという問題が出て、問題の意味もまったくわからないのでヒントください。 問題 数独を解くプログラムを作成せよ。ただし、すでに埋まっているマスを入力する時にはi,j,n(改行)でひとつの数字を入力できるものとし、終了条件は、0,0,0を入力するとする。 問題用紙には1問だけ数独が載ってあるのですが、 初歩的な質問で申し訳ありませんが まずこのプログラムは、その1問だけ載っているマスが少し埋まっているプログラムを打ち込んでから解くプログラムを考えるのでしょうか? 普通、数独を解くプログラムとは、空いているマスにキーボード入力して、解くのでしょうか?それとも自動に動いて解くのでしょうか? はじめにプログラムをコンパイルしたときにどう言葉が出るようにすればようのでしょうか? 終了条件0,0,0とは、000を入力したら終わる?ということでしょうか? マスを作って、クリックすると数字が…というようなjavaは習ってなくコマンドプロントでコンパイルだけなので、数字を打って入力、エンターというだけで解くのだと思うのですが、まったくわからないです。 根本的にわからなくてすいません。 ぜひご回答よろしくおねがいします。

  • 数独をとくプログラム

    C初心者です。大学生です。 タイトルの通り、Cで数独を解くプログラムを考えています。 数独については http://www.nikoli.co.jp/puzzles/1/ をご参照ください。 で、数独にも難易度があり、初めからある程度数字が埋まっている(簡単な) 問題を解くプログラムは作ることが出来ました。 単純に、各マスの構造体Cellに対してsign[1],sign[2],,,,,sign[9]を定義し、 それが1なら可能性あり、0なら可能性なし、として (例えばsign2]==1,sign[5]==0ならそのマスは2になる可能性はあるが5になることはない) 丹念に各マスに対してそのマスが属するブロック、列、行を調べて最後まで1であるflagを探すようにしたのです。 しかし初めから埋まっている数字が少ないと(難しいと)そもそも回答が1通りでない、 などの理由から上記のアルゴリズムでは解くことが出来ません。 あきらかにどこかをあてずっぽに仮定する作業(バックトラック?) が必要になりそうです。 ・・・が、それをどうやって実現したらいいかで行き詰っています。 どうか知恵を貸してください。よろしくお願いいたします。。。

  • 数独を解くアルゴリズム

    数独を解くプログラムを再帰呼び出しなしで作ろうとしています。丁度このウェブサイト(http://sudoku.klaas.nl/)のアプレットと同じアルゴリズムが作りたいんです。 まず一番左上はしから始め、現在のセルに入れることのできる解を全てリスト化して、その一つをそのセルに入れます。次のセルに移り同じことを続けていきます。これを、解のないセルに行きあたるまでつづけていき、行き詰まった場合は一つもどり、別の解を選択したのち、次のセルに進みます。 私の作った数独のプロゴラムには、undoメソッドがあるので、これを使って前のセルに戻ることができるようにしています。 色々ためして見ましたが、うまくいくいきません。どなたか簡単なやり方があったら教えてください。

  • 数独の3国同盟のアルゴリズム教えて下さい

    はじめまして! C言語を勉強して3ヶ月になります、現在、勉強のつもりで数独の解法プログラムを作っています が、解法プログラムを基本から順に実装しようと基本から2国同盟まではわかったのですが3国 同盟以上(まずは自明のNaked Tripleからお願いします<(_ _)>)のアルゴリズムがどうしても 解らずプログラムが書けません。マスの絞り込み方です。例えば横ラインのマスで候補数が2、 3個のマスに絞って・・・次ですが3個のマスには3種類しか入らない。・が解りません!目 で見ればわかりますがそれをプログラムする方法)NAKED(見える)Tripleだけで良いので考え方 を教えて下さい。2日間詰まってます(>< ) どうぞ宜しくお願いします<(_ _)> (例) R3横一行だけを考えたときにR3C1(6,8)、R3C2(1,6)、R3C3(2,3,4)、R3 C4(1,8)、R3C5(1,2,4,5,6)・・・で()内は候補数です。これはC1、C2、C4で (1,6,8)の3国同盟ができています。R3C5の(1,6)は削除され候補数(2,4, 5)となる。悩んでいるのはC1、C2、C4を同盟決定のアルゴリズムです。 「異なる3つのマスを選んだときに、それら3マスに入れられる候補の種類が3種類であること」を プログラム上でどう表現したら良いかずっと詰まってます(>< ) どう考えたらこの3つのマスを決定(同盟関係)できるのでしょうか?宜しくお願い致します<(_ _)>

  • エクセルVBAで数独

     エクセルのVBAを使って、ナンバープレイス(数独?)の問題を創りたいのですが、どうすれば良いでしょう?  一応、以下の条件で自分で組んでみました。  ○各マス目で、「縦9マス」「横9マス」「3×3マス」中に有る数字を【1~9】内から消去し、残った数字内からランダムで挿入する数字を決定する。  ○処理中に、どうしても決定できないマス目が発生した場合は、決定済みのマス目をある程度チャラにし(処理を戻って)やり直す。  ○上記方法で、1~81までのマス目を埋めていく。  ○最後に、適当な数のマス目の数字を消去する。  一問作成するのに結構な時間がかかる上、時には完成しない(やり直し続ける)事態が発生します。  何か良い方法(アルゴリズム?)が有ったらご教示願います。  (…アルゴリズムを質問するのは、カテゴリー違いでしょうか?)

  • 数独かを判断するプログラム

    私が作ろうとしているプログラムは数独を解くものではなく、予めテキストファイルに書かれている横9つ縦9つ、計81個の数字の表が、数独として成り立っているかを判断するものです。 数独についてはこちらで http://ja.wikipedia.org/wiki/数独 or http://sudoku.ara3.net/rule.htm 配列をa[9][9]と用意し、テキストファイルから数字を左上から順に配列に確保していき、その表が数独かどうか判断する段階で躓いています。3×3のマスの中に1~9までの数字が1個ずつあり、かつそのマスが計9つあれば数独なので、まず最初の3×3のマスの中の数字を1~9まで確認し、それを残り8つのマスにも同様に繰り返すだけで良いと思うのですが、その方法がわからず困っています。どなたかお解かりになる方、よろしくお願いします。 例として、テキストファイルの数字の表は以下の様になっています。 1 2 3 4 5 6 7 8 9 4 5 6 7 8 9 1 2 3 7 8 9 1 2 3 4 5 6 2 3 4 5 6 7 8 9 1 5 6 7 8 9 1 2 3 4 8 9 1 2 3 4 5 6 7 3 4 5 6 7 8 9 1 2 6 7 8 9 1 2 3 4 5 9 1 2 3 4 5 6 7 8 ちなみにこの表は数独として成り立っています。

  • 数独の解き方

    8月17日付け東京新聞サンデー版の数独 「マスに入れられない数字を考える解法もある」 というヒントがあります。 まったくお手上げです。 問題と解答をアップしました。 解き方を教えて下さい。 問題 http://img179.imageshack.us/img179/4592/43017024hd8.th.jpg 回答 http://img210.imageshack.us/img210/715/18709358hh8.th.jpg 問題にABC… abc…を付けましたので宜しくお願い致します。

  • 最近、数独にはまっています。

    最近、数独にはまっています。 マスに可能性のある数字を書きこみながら何とか色々チャレンジしてきたのですが、 今回ものすごい難しい問題にぶち当たりました。 最初にどこに注目して解いていけば良いのか? その手掛かりから、解いていく道筋を教えていただけませんでしょうか? 宜しくお願いします。 問題です。 5***4***9 **81*54** *3*****5* *8*3*7*1* 2*******3 *7*6*2*4* *1*****9* **72*98** 8**57***4 お願いします

  • この数独を解けますか?6

    従来の数独問題が簡単過ぎるので、 新たに「16×16」の問題を作ってみました。 ルールは従来と同様、 (1)1×16 (2)16×1 (3)4×4 のマスに、1から16の数字を重複することなく埋める。 です。 正解者には、ひとつ上の問題「25×25」の挑戦権をプレゼント! その正解者には、その上の問題「36×36」の挑戦権をプレゼント! 解答・感想等、お待ちしております。 関連質問の以下を合わせてご覧ください。 この独数を解けますか?3 http://okwave.jp/qa/q6322421.html この数独を解けますか?4 http://okwave.jp/qa/q6324308.html この数独を解けますか?5 http://okwave.jp/qa/q6328529.html

  • 数独の問題レベル決定のコツ

     9×9マス全てに数独のルール通り、重複無く「1~9」の数字を入れた後、適当数(一般的な問題で有る位)の空白を作り問題を完成させたいのです。    上記のやり方で、回答が1つだけになるようにしたい時、どのようにに空白を作れば難易度の調整が出来るのでしょうか?  空白場所を決定する『コツ』が有れば、お教えください。