กลับไปยังโจทย์
ปานกลาง 0 ข้อที่แก้แล้ว อัตราผ่าน 0%

การค้นหา A* บนตารางที่มีน้ำหนัก

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

สิ่งที่คุณจะได้เรียนรู้

  • หาเส้นทางที่ถูกที่สุดด้วยคิวลำดับความสำคัญ
  • ใช้ระยะทางแมนฮัตตันเป็นฮิวริสติก
  • เข้าใจว่าทำไมฮิวริสติกที่ยอมรับได้จึงยังให้คำตอบดีที่สุด

โจทย์

A* คืออัลกอริทึมหาเส้นทางแบบคลาสสิกในเกมและหุ่นยนต์ มันสำรวจช่องตามลำดับของ f = g + h โดย g คือค่าใช้จ่ายที่จ่ายไปแล้ว และ h คือค่าประมาณแบบฮิวริสติกของค่าใช้จ่ายที่เหลือ

ตารางเก็บค่าใช้จ่ายของแต่ละช่อง: การเข้าไปในช่องหนึ่งเสียค่าเท่ากับค่าของช่องนั้น และ 0 คือกำแพงที่เข้าไปไม่ได้ คุณเริ่มที่ start (ไม่ต้องจ่ายค่าของช่องนี้) และเดินขึ้น ลง ซ้าย หรือขวาได้

ใช้ A* โดยมีระยะทางแมนฮัตตัน |row - goal_row| + |col - goal_col| เป็นฮิวริสติก ทุกช่องที่เดินได้มีค่าอย่างน้อย 1 ฮิวริสติกนี้จึงไม่เคยประมาณเกิน และ A* จะคืนคำตอบที่เหมาะสมที่สุด

จง implement a_star_cost(grid, start, goal)

อินพุต

grid: เมทริกซ์ค่าใช้จ่ายของแต่ละช่อง (0 = กำแพง)

start, goal: ตำแหน่งในรูป [row, col]

เอาต์พุต

คืนค่าใช้จ่ายรวมที่น้อยที่สุดเพื่อไปถึง goal หรือ -1 ถ้าไปไม่ถึง (รวมถึงกรณีที่ start หรือ goal เป็นกำแพง)

เงื่อนไข

1 ≤ จำนวนแถว, จำนวนคอลัมน์ ≤ 100

0 ≤ แต่ละค่าใช้จ่าย ≤ 9

ตัวอย่าง

ตัวอย่างที่ 1
อินพุต:
goal = [2, 2]
grid = [
    [1, 1, 1],
    [1, 0, 1],
    [1, 1, 1]
]
start = [0, 0]

ผลลัพธ์ที่คาดหวัง:
expected = 4
อินพุต:
std::vector<long long> goal = {2, 2};
std::vector<std::vector<long long>> grid = {
    {1, 1, 1},
    {1, 0, 1},
    {1, 1, 1}
};
std::vector<long long> start = {0, 0};

ผลลัพธ์ที่คาดหวัง:
long long expected = 4;
อินพุต:
long[] goal = new long[] {2, 2};
long[][] grid = new long[][] {
    new long[] {1, 1, 1},
    new long[] {1, 0, 1},
    new long[] {1, 1, 1}
};
long[] start = new long[] {0, 0};

ผลลัพธ์ที่คาดหวัง:
long expected = 4;

คำอธิบาย

ช่องกลางเป็นกำแพง เดินขวาสองครั้งแล้วลงสองครั้ง (หรือลงก่อนแล้วไปขวา) จะเข้าช่องค่า 1 สี่ช่อง รวมเป็น 4

ตัวอย่างที่ 2
อินพุต:
goal = [0, 2]
grid = [
    [1, 9, 1],
    [1, 9, 1],
    [1, 1, 1]
]
start = [0, 0]

ผลลัพธ์ที่คาดหวัง:
expected = 6
อินพุต:
std::vector<long long> goal = {0, 2};
std::vector<std::vector<long long>> grid = {
    {1, 9, 1},
    {1, 9, 1},
    {1, 1, 1}
};
std::vector<long long> start = {0, 0};

ผลลัพธ์ที่คาดหวัง:
long long expected = 6;
อินพุต:
long[] goal = new long[] {0, 2};
long[][] grid = new long[][] {
    new long[] {1, 9, 1},
    new long[] {1, 9, 1},
    new long[] {1, 1, 1}
};
long[] start = new long[] {0, 0};

ผลลัพธ์ที่คาดหวัง:
long expected = 6;

คำอธิบาย

เดินผ่านช่อง 9 ตรง ๆ เสีย 9 + 1 = 10 แต่ถ้าเดินลง ไปตามแถวล่างสุด แล้วขึ้นกลับมา จะเข้าช่องค่า 1 หกช่อง รวมเป็น 6

แนวทางการแก้

ลองทำเองก่อน แล้วค่อยเปิดคำใบ้ทีละข้อ

คำใบ้ 1

ใช้ priority queue ที่จัดลำดับด้วยต้นทุนที่เดินมาแล้วบวก Manhattan distance ไปยังเป้าหมาย

คำใบ้ 2

เก็บต้นทุนที่ดีที่สุดที่พบสำหรับแต่ละช่อง และขยายช่องนั้นก็ต่อเมื่อเส้นทางนี้ดีกว่าเดิม

คำใบ้ 3

ถือว่า wall และช่องเริ่มหรือเป้าหมายที่ถูกบล็อกเป็นไปไม่ได้ และจำไว้ว่าการเข้าช่องเริ่มต้นไม่มีค่าใช้จ่าย

ความซับซ้อนที่คาดหวัง

เวลา O(rows * cols log(rows * cols)), หน่วยความจำเพิ่ม O(rows * cols)

แหล่งอ้างอิง

โจทย์นี้ปรับให้เหมาะกับ CodeUtility กรุณาทำตามคำชี้แจงและข้อจำกัดด้านบน

เรียนรู้จากคนอื่น

แนวทางจากชุมชน

ยังไม่มีวิธีทำที่เผยแพร่ ลองแก้โจทย์นี้เพื่อแชร์วิธีแรก