3
最短時間でこの数字パズルのすべての解決策を見つける
歴史 私の会社は、毎週のニュースレターを社内の全員に送信しています。これらのニュースレターには、先週のなぞなぞの解決策を最初にメールしたり提供したりした会社の誰に対しても叫び声とともに、なぞなぞが含まれています。これらのなぞなぞのほとんどは非常に些細なものであり、正直なところハイテク企業にとってはかなり退屈なものですが、数か月前に私が注意を引いたものがありました。 オリジナルのなぞなぞ: 以下の形状を考えます: 1〜16の自然数があります。すべての連続する行と連続する列の合計が29になるように、すべてをこの形状に合わせます。 たとえば、このパズルに対するそのようなソリューション(ニュースレターに提出した「標準的な」ソリューション)は次のとおりです。 しかし、それを解決する過程で、かなり興味深い情報を見つけました。 それよりもはるかに多くのソリューションがあります。実際、9,368のソリューションがあります。 ルールセットを拡張して、行と列が29である必要はなく、互いに等しいことだけを要求する場合、33,608のソリューションが得られます。 合計27の4,440のソリューション。 合計28の7,400のソリューション。 29の合計のための9,368のソリューション。 合計30の6,096のソリューション。 合計31の5,104ソリューション。 合計32の1,200ソリューション。 だから私と私の同僚(主に私のマネージャーは、「一般目的」のプログラミングスキルを持っている私以外の唯一の人物だったので)は、1か月のほとんど続いた挑戦に着手しました。関連する義務-可能な限り迅速にすべてのソリューションを見つけるプログラムを作成しようとするために。 元の統計 問題を解決するために私が書いた最初のプログラムは、単にランダムな解決策を何度もチェックし、解決策が見つかった時点で停止しました。この問題について数学的分析を行ったことがあれば、おそらくこれが機能してはならないことをすでに知っているでしょう。しかし、どういうわけか私は幸運に恵まれ、プログラムが1つのソリューション(上記で投稿したもの)を見つけるのに1分しかかかりませんでした。プログラムを繰り返し実行すると、多くの場合10〜20分かかるため、これは明らかに問題の厳密な解決策ではありませんでした。 パズルのあらゆる可能な順列を反復する再帰的ソリューションに切り替え、合計していない合計を削除することで、多くのソリューションを一度に破棄しました。IE私が比較した最初の行/列が既に等しくなかった場合、パズルに入れ替わったものがそれを変更しないことを知って、そのブランチのチェックをすぐに停止できました。 このアルゴリズムを使用して、最初の「適切な」成功が得られました。プログラムは、約5分で33,608のソリューションすべてを生成して吐き出すことができました。 私のマネージャーは異なるアプローチを持っていました:私の仕事に基づいて、可能な解決策は27、28、29、30、31、または32の合計しかないと知っていたので、彼はそれらの特定の値についてのみ可能な合計をチェックするマルチスレッドソリューションを書きました。彼はわずか2分でプログラムを実行することができました。だから私は再び繰り返しました。可能なすべての3/4桁の合計をハッシュし(プログラムの開始時に、合計ランタイムでカウントされます)、行の「部分合計」を使用して、以前に完了した行に基づいて、以前に完了した行に基づいて残りの値を検索しました残りのすべての値をテストし、時間を72秒に短縮しました。その後、いくつかのマルチスレッドロジックを使用して、40秒に短縮しました。私のマネージャーは、プログラムを家に持ち帰り、プログラムの実行方法についていくつかの最適化を実行し、12秒に短縮しました。行と列の評価を並べ替え、 私たちのどちらかが1か月後にプログラムを取得した最速の時間は、マネージャーが0.15秒、私が0.33秒でした。私のマネージャーのプログラムはすべての解決策を見つけましたが、それらをテキストファイルに出力しなかったので、私は私のプログラムがより高速であると主張しました。彼がコードにそのロジックを追加した場合、多くの場合、0.4〜0.5秒かかりました。 私たちは、以来、生存するまで、当社内の個人的な挑戦を許されましたが、当然のことながら、質問の遺跡は:することができます。このプログラムは高速化できますか? それが私が皆さんに提起する挑戦です。 あなたの挑戦 私たちが取り組んだパラメーターは、「29の合計」ルールを緩和し、代わりに「すべての行/列の合計が等しくなる」ようにしました。このルールを皆さんにも設定します。したがって、課題は次のとおりです。この謎に対するすべての解決策を可能な限り短時間で発見(および印刷!)するプログラムを作成します。提出されたソリューションに上限を設定します。比較的まともなコンピューター(<8歳)でプログラムに10秒以上かかる場合、カウントするには遅すぎる可能性があります。 また、パズルにはいくつかのボーナスがあります: ソリューションを一般化して、16個の数値のセットだけでなく、それでも機能するようにできますint[1,16]か?タイミングスコアは、元のプロンプト番号セットに基づいて評価されますが、このコードパスを通過します。(-10%) 重複した数値を適切に処理して解決する方法でコードを記述できますか?これは見かけほど簡単ではありません!「視覚的に同一」のソリューションは、結果セット内で一意である必要があります。(-5%) 負の数を処理できますか?(-5%) あなたもすることができますしようとハンドルがの浮動小数点数というソリューションを生成するが、それは全く失敗した場合はもちろん、ショックを受けることはありません。しかし、堅牢なソリューションを見つけた場合、それは大きなボーナスの価値があるかもしれません! すべての意図と目的に対して、「回転」はユニークなソリューションと見なされます。したがって、異なるソリューションの単なるローテーションであるソリューションは、独自のソリューションとしてカウントされます。 コンピューターで作業しているIDEはJavaとC ++です。他の言語からの回答を受け入れることもできますが、コードのセットアップが容易なランタイム環境を入手できる場所へのリンクも提供する必要があります。