Розуміння зворотного відстеження в C ++


12

Я добре розумію основи С ++, я також розумію, як працює і рекурсія. Я зіткнувся з певними проблемами, такими як класична проблема восьми цариць і вирішення судоку з Backtracking.

Я усвідомлюю, що я сильно розгубився, коли справа доходить до цього, я, здається, не зможу зрозуміти концепцію повернутися в стек рекурсії та знову почати, щоб вирішити проблему. З пером та папером це здається простим, але коли мова йде про написання коду для цього, я розгублений, як почати атакувати ці проблеми.

Було б корисно, якби був навчальний посібник, орієнтований на початківців на зворотній трек, або якщо була б хороша книга, де це було висвітлено. Якщо хтось може пролити світло на цю тему або дати мені посилання на гідні посилання, я буду дуже вдячний.

І так, я знаю, що в функціональних мовах було б простіше, але я хотів би зрозуміти реалізацію і в імперативних мовах.


Я думаю, що це гарне запитання, але я думаю, що було б краще підкреслити прохання, щоб хтось пояснив зворотній трек над запитами навчальних посібників чи інших ресурсів. У відповідь на поглиблене пояснення будь-який день описується список посилань.
Адам Лір

Було б ідеально, якби хтось міг дати детальне пояснення, але я також не проти прочитати посилання. Просто я не знаю, з чого почати.
nikhil

Відповіді:


9

... Я, здається, не зможу зрозуміти концепцію повернення в стеку рекурсії та початку знову для вирішення проблеми.

У зворотному треку ви не починаєте знову. Натомість ви повторюєте всі варіанти в поточній ситуації.

Подумайте, як знайти рішення для лабіринту. У один момент, коли у вас є два різні шляхи, ви спершу спробуйте зліва. Якщо лівий не веде вас до виходу, ви повернетесь до пункту і спробуйте інший шлях. Ось як працює зворотний трек. У 8 Q та інших проблемах, де можна використовувати зворотний трекінг, заплутана частина знаходиться в проблемній області - як переглядати ваші варіанти в тій чи іншій ситуації детермінованим способом.

EDIT : далі псевдо-код допомагає зрозуміти зворотній трек.

# 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_ разрешило б перевірити, чи всі королеви є на дошці і чи добре вони між собою.
  • 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));}немає необхідності в киданні для очікуваного результату
храповик урод

@ratchet: Абсолютно. Це теж ідеально хороший спосіб зробити це. (Я просто намагався згорнути приклад. Я насправді зробив би це по-своєму.)
Майк Данлаве

@MikeDunlavey різання є важливим на практиці, хоча.
jupp0r
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.