การทำความเข้าใจย้อนรอยใน C ++


12

ฉันมีความเข้าใจพื้นฐานที่ดีเกี่ยวกับพื้นฐานของ C ++ ฉันยังมีความเข้าใจว่าการเรียกซ้ำใช้งานอย่างไร ฉันเจอปัญหาบางอย่างเช่นปัญหาแปดคลาสสิกและแก้ปัญหา Sudoku ด้วย Backtracking

ฉันรู้ว่าฉันค่อนข้างหลงทางเมื่อพูดถึงเรื่องนี้ฉันไม่สามารถเข้าใจแนวคิดของการย้อนกลับไปในกองการเรียกซ้ำและเริ่มต้นอีกครั้งเพื่อแก้ไขปัญหา มันดูง่ายด้วยปากกาและกระดาษ แต่เมื่อพูดถึงการเขียนโค้ดสำหรับเรื่องนี้ฉันก็สับสนว่าจะเริ่มโจมตีปัญหาเหล่านี้อย่างไร

มันจะมีประโยชน์ถ้ามีบทช่วยสอนที่มุ่งเป้าไปที่ผู้เริ่มต้นเพื่อย้อนรอยหรือถ้ามีหนังสือที่ดีที่หนังสือเล่มนี้ถูกปกคลุม หากใครบางคนสามารถทำให้กระจ่างในหัวข้อนี้หรือให้ลิงก์ไปยังการอ้างอิงที่เหมาะสมฉันจะขอบคุณจริงๆ

และใช่ฉันรู้ว่ามันจะง่ายขึ้นในภาษาที่ใช้งานได้ แต่ฉันต้องการที่จะเข้าใจการใช้งานในภาษาที่จำเป็นด้วย


ฉันคิดว่านี่เป็นคำถามที่ดี แต่ฉันคิดว่ามันจะเป็นการดีกว่าที่จะเน้นย้ำคำขอสำหรับคนที่จะอธิบายการย้อนรอยการขอบทเรียนหรือแหล่งข้อมูลอื่น ๆ คำอธิบายในเชิงลึกประเภทคำตอบเต้นรายการอ้างอิงทุกวัน
อดัมเลียร์

มันจะสมบูรณ์แบบถ้าใครบางคนสามารถให้คำอธิบายโดยละเอียด แต่ฉันก็ไม่รังเกียจที่จะอ่านข้อมูลอ้างอิงด้วย เป็นเพียงที่ฉันไม่รู้ว่าจะเริ่มจากตรงไหน
nikhil

คำตอบ:


9

... ดูเหมือนว่าฉันจะไม่สามารถเข้าใจแนวคิดของการย้อนกลับไปในกองการเรียกซ้ำและเริ่มต้นอีกครั้งเพื่อแก้ไขปัญหา

ในการย้อนรอยคุณจะไม่เริ่มต้นอีกครั้ง คุณทำซ้ำตัวเลือกทั้งหมดในสถานการณ์ปัจจุบันแทน

คิดหาวิธีแก้ปัญหาให้เขาวงกต เมื่อถึงจุดหนึ่งที่คุณมีเส้นทางที่แตกต่างกันสองเส้นทางคุณจะลองทางซ้ายก่อน หากทางซ้ายไม่นำคุณไปสู่ทางออกคุณจะกลับไปที่จุดนั้นและลองเส้นทางอื่น นั่นเป็นวิธีที่การย้อนรอยทำงาน ใน 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) สำหรับการมอบหมายคืออัลกอริธึมการแก้เขาวงกต
Gerry

รู้ถึงการมอบหมายง่ายๆที่ฉันสามารถเขียนรหัสเพื่อรับความรู้สึกที่แท้จริงของสิ่งนี้
nikhil

@nikhil: คุณถามว่ามีปัญหาง่าย ๆ บ้างไหม? มันเป็นการดีกว่าที่จะเขียนโค้ดหลอกเพื่อแสดงเส้นทางทั่วไปของการย้อนรอย ฉันจะลองอีกครั้งในการตอบกลับ
Codism

ใช่ว่าจะเป็นประโยชน์มากที่สุด
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));}ไม่จำเป็นต้องโยนเพื่อผลที่คาดหวัง
วงล้อประหลาด

@ วงล้อ: แน่นอน นั่นเป็นวิธีที่ดีอย่างสมบูรณ์แบบที่จะทำ (ฉันแค่พยายามขจัดความยุ่งเหยิงตัวอย่างจริง ๆ แล้วฉันจะทำตามที่คุณต้องการ)
Mike Dunlavey

@MikeDunlavey การตัดมีความสำคัญในทางปฏิบัติแม้ว่า
jupp0r
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.