Memahami Backtracking di C ++

12

Saya memiliki pemahaman dasar yang baik tentang dasar-dasar C ++, saya juga memiliki pemahaman tentang bagaimana rekursi bekerja juga. Saya menemukan masalah tertentu seperti masalah delapan ratu klasik dan memecahkan Sudoku dengan Backtracking.

Saya menyadari bahwa saya cukup tersesat dalam hal ini, saya sepertinya tidak dapat mengalihkan pikiran tentang konsep kembali ke tumpukan rekursi dan memulai lagi untuk menyelesaikan masalah. Tampaknya mudah dengan pena dan kertas tetapi ketika harus menulis kode untuk ini, saya bingung bagaimana cara mulai menyerang masalah ini.

Akan sangat membantu jika ada tutorial yang ditujukan untuk pemula untuk melakukan backtracking atau jika ada buku bagus yang membahas hal ini. Jika seseorang dapat menjelaskan topik ini atau memberi saya beberapa tautan ke referensi yang layak, saya akan sangat berterima kasih.

Dan ya saya tahu bahwa itu akan lebih mudah dalam bahasa fungsional tetapi saya ingin memahami implementasi dalam bahasa imperatif juga.

nikhil
sumber
Saya pikir ini adalah pertanyaan yang bagus, tapi saya pikir akan lebih baik untuk menekankan permintaan seseorang untuk menjelaskan pengunduran diri saat meminta tutorial atau sumber daya lainnya. Jenis jawaban penjelasan mendalam mengalahkan daftar referensi setiap hari.
Adam Lear
Akan sempurna jika seseorang dapat memberikan penjelasan yang terperinci, tetapi saya juga tidak keberatan membaca referensi. Hanya saja saya tidak tahu harus mulai dari mana.
nikhil

Jawaban:

9

... Saya sepertinya tidak bisa memikirkan konsep untuk kembali ke tumpukan rekursi dan mulai lagi untuk menyelesaikan masalah.

Di mundur, Anda tidak memulai lagi. Sebaliknya, Anda beralih melalui semua opsi pada situasi saat ini.

Pikirkan tentang menemukan solusi untuk labirin. Pada satu titik di mana Anda memiliki dua jalur berbeda, Anda coba yang kiri terlebih dahulu. Jika yang kiri tidak membawa Anda ke jalan keluar, Anda kembali ke titik dan mencoba jalur lainnya. Begitulah cara backtracking bekerja. Dalam 8 Q dan masalah lain di mana backtracking dapat digunakan, bagian yang membingungkan ada di domain masalah - bagaimana cara mengulangi pilihan Anda dalam situasi tertentu dengan cara deterministik.

EDIT : berikut ini adalah kode semu yang membantu memahami penelusuran ulang.

# 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

Untuk pertanyaan 8Q:

  • state.get_all_options akan mengembalikan daftar posisi yang memungkinkan untuk ratu berikutnya
  • state.is_resolved akan menguji apakah semua ratu berada di papan tulis dan apakah mereka baik satu sama lain.
  • state.apply dan state.undo akan memodifikasi papan untuk menerapkan atau membatalkan penentuan posisi.
Codism
sumber
Kode rekursif pertama yang saya tulis (pada tahun 1984 menggunakan Pascal) untuk tugas adalah algoritma penyelesaian labirin.
Gerry
Ketahui beberapa tugas sederhana di mana saya benar-benar dapat menulis kode untuk mendapatkan kesan sebenarnya dari barang ini.
nikhil
@nikhil: apakah Anda bertanya apakah ada masalah sederhana? Lebih baik menulis beberapa kode pseudo untuk mendemonstrasikan routing generik dari backtracking. Saya akan mencobanya nanti sebagai balasan.
Codism
Ya persis, itu akan sangat membantu.
nikhil
Terima kasih banyak, saya telah membaca beberapa hal belakangan ini. Perlahan tapi pasti pemahaman saya meningkat.
nikhil
5

Anda telah melihat program berjalan pohon biner, kan? Ini terlihat seperti ini:

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)
  }
}

Ini pengunduran diri Anda.

Anda sebenarnya tidak membutuhkan pohon fisik. Yang Anda butuhkan adalah cara untuk bergerak dan kemudian membatalkannya, atau memberi tahu apakah Anda menang, atau memberi tahu apakah Anda tidak bisa melangkah lebih jauh.

Mike Dunlavey
sumber
1
Anda tidak dapat mengembalikan bool / int untuk memeriksa apakah solusinya ditemukan di subtree? else{return walk(p->left)||walk(p->right));}tidak perlu untuk melempar hasil yang diharapkan
ratchet freak
@ scratchet: Tentu saja. Itu juga cara yang sangat baik untuk melakukannya. (Saya hanya mencoba untuk mengacaukan contoh. Saya benar-benar akan melakukannya dengan cara Anda.)
Mike Dunlavey
Pemotongan @MikeDunlavey agak penting dalam praktiknya.
jupp0r