C ++のバックトラッキングを理解する


12

私はC ++の基本について十分に基本的な理解を持っています。また、再帰がどのように機能するかも理解しています。私は、古典的な8つのクイーンの問題やバックトラックで数独を解くなどの特定の問題に遭遇しました。

これに関してはかなり迷っていることに気づきました。再帰スタックに戻って問題を解決するためにやり直すという概念を思い浮かべることができないようです。ペンと紙で簡単に思えますが、このためのコードを書くことになると、これらの問題への攻撃を開始する方法について混乱しています。

バックトラックの初心者向けのチュートリアルがある場合や、これが取り上げられている良い本がある場合に役立ちます。誰かがこのトピックに光を当てるか、まともな参考文献へのリンクを教えてくれれば、本当にありがたいです。

そして、はい、関数型言語の方が簡単であることは知っていますが、命令型言語の実装についても理解したいと思います。


これは良い質問だと思いますが、チュートリアルや他のリソースを求めるよりも、誰かにバックトラックを説明してほしいという要求を強調した方が良いと思います。詳細な種類の答えは、いつでも参照リストに勝ります。
アダムリア

誰かが詳細な説明をすることができれば完璧でしょうが、私も参考文献を読むことを気にしません。どこから始めればいいのか分からない。
-nikhil

回答:


9

... 再帰スタックに戻り、問題を解決するために再度開始するという概念を思いつかないようです。

バックトラックでは、再び開始することはありません。代わりに、現在の状況ですべてのオプションを反復処理します。

迷路の解決策を見つけることを考えてください。2つの異なるパスがある時点で、左側のパスを最初に試します。左側の出口で出口につながらない場合は、ポイントに戻って別のパスを試してください。それがバックトラッキングの仕組みです。バックトラッキングを使用できる8 Qおよびその他の問題では、混乱する部分は問題領域にあります。特定の状況でオプションを決定論的に反復する方法です。

編集:以下は、バックトラックを理解するのに役立つ擬似コードです。

# depending on the problem, backtracking is not necessarily calling the
# method itself directly. for now, let's just stick with the simple case.

def backtracking(state)
  option_list = state.get_all_options
  option_list.each {|option|
    state.apply option
    return resolved if state.is_resolved
    return resolved if backtracking(state) == resolved
    state.undo option
  }
  return not_resolved
end

8Qの質問:

  • state.get_all_optionsは、次のクイーンの可能な位置のリストを返します
  • state.is_resolvedは、すべてのクイーンがボードに載っているかどうか、またお互いが良いかどうかをテストします。
  • state.applyおよびstate.undoは、位置決めを適用または取り消すためにボードを変更します。

割り当てのために(1984年にPascalを使用して)私が書いた最初の再帰コードは、迷路解決アルゴリズムでした。
ジェリー

このようなものの実際の感触を得るために実際にコードを書くことができるいくつかの簡単な割り当てを知っています。
-nikhil

@nikhil:簡単な問題があるかどうか尋ねていますか?バックトラッキングの一般的なルーティングを示すために、いくつかの擬似コードを記述する方が適切です。返信で後で試します。
コーディズム

はい、まさにそれが最も役立ちます。
-nikhil

どうもありがとう、私は最近いくつかのものを読んでいます。ゆっくりですが着実に私の理解は向上しています。
-nikhil

5

バイナリツリーを歩くプログラムを見ましたか?次のようになります。

void walk(node* p){
  if (p == NULL) return;  // this is backtracking
  else if (WeWin(p)){
    // print We Win !!
    // do a Throw, or otherwise quit
  }
  else {
    walk(p->left);   // first try moving to the left
    walk(p->right);  // if we didn't win, try moving to the right
                     // if we still didn't win, just return (i.e. backtrack)
  }
}

バックトラックがあります。

実際には物理的なツリーは必要ありません。必要なのは、移動して後で元に戻す方法、勝ったかどうか、それ以上先に進むことができないかどうかを伝える方法だけです。


1
bool / intを返して、サブツリーで解決策が見つかったかどうかを確認できませんか?期待される結果のelse{return walk(p->left)||walk(p->right));}ために投げる必要はありません
ラチェットフリーク

@ラチェット:もちろん。それはそれを行うための完全に良い方法でもあります。(私は単に例を
整理

ただし、@ MikeDunlaveyの切断は実際には重要です。
jupp0r
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.