เราใช้คุ๊กกี้บนเว็บไซต์ของเรา กรุณาอ่านและยอมรับ นโยบายความเป็นส่วนตัว เพื่อใช้บริการเว็บไซต์ ไม่ยอมรับ
de algorismokratui++
Basic DP II : Optimal Substructure
  • ปัญหาอีกรูปแบบที่ใช้ DP แก้ได้คือปัญหาที่มีปัญหาย่อย ๆ ซ้อนกัน และคำตอบของปัญหาใหญ่เกิดจากคำตอบที่ดีที่สุดของปัญหาย่อย

    หมายความว่ายังไง? ขอยกตัวอย่างโจทย์ใน OTOG ข้อนึงละกัน แต่เพื่อไม่ให้ถือว่าเป็นการสปอยโจทย์ เราจะเปลี่ยนเรื่องราวสักหน่อย และไม่บอกว่าเป็นข้อไหน :3

    ปัญหา : เราเป็นฮีโรต้องเดินเก็บเวลบนตารางสี่เหลี่ยม แต่เราเดินได้แค่ลงหรือขวาเท่านั้น ทีนี้บางช่องดันมีมอนส์เตอร์โคตรโหดที่จะฆ่าเราตายอย่างเขียดโดนเหยียบ ทำให้เราเสียเวลไปฟรี ๆ โดยแต่ละช่องจะมีค่า EXP ที่ได้ / เสียต่างกัน โดยถ้าเสียจะมีค่าเป็น - 
    ตัวอย่าง :
    4 5
    80 41 68 -100
    -150 70 62 65
    77 -105 96 97
    82 100 -110 -105
    98 105 120 98
    ทำยังไงครับข้อนี้? วิธีที่โง่ที่สุด (Naive Solution) คือไล่ DFS ไปทุกทางที่เป็นไปได้

    void dfs(int x, int y, int xp) {
    int xp += board[y][x];
    if (x == m-1 && y == n-1)
    glob_max = max(glob_max, ex);
    if (x<m-1)
    dfs(x+1, y, xp);
    if (y<n-1)
    dfs(x, y+1, xp);
    }

    วิธีนี้จะใช้  O((m+n)((m+n)!/m!n!)) เมื่อ m และ n คือขนาดของตาราง  ซึ่งบอกตรง ๆ ว่ามันห่วยแตกสุด ๆ ไปเลย

    วิธีที่ดีกว่าคือใช้ DP เข้าช่วย เราจะสังเกตุได้ว่าจำนวนเวลที่ได้มากที่สุดของแต่ละช่องคือจำนวนเวลในช่องนั้น ๆ + กับเวลที่มากสุดของช่องก่อนหน้า ว่ากันง่าย ๆ

    best(x,y) = xp(x,y) + max(best(x-1,y), best(x,y-1))

    นี่คือที่ว่าคำตอบที่ดีที่สุดของปัจจุบันเกิดจากคำตอบที่ดีที่สุดของปัญหาย่อย ๆ (ปัญหาย่อยคือเส้นทางก่อนหน้าที่มายังจุดปัจจุบันได้)

    รู้แบบนี้เราจึงไล่ลูปธรรมดาได้เลย โดยมี base case คือ แถวขอบด้านบน และ ซ้ายมีวิธีไปแค่วิธีเดียวเท่านั้นคือมาจากทางซ้าย และจากข้างบนตามลำดับ
    // setup base condition
    best[0][0] = board[0][0];
    for(int i=1; i<m; i++)
    best[0][i] = best[0][i-1]+board[0][i];
    for(int i=1; i<n; i++)
    best[i][0] = best[i-1][0]+board[i][0];
    // DP
    for (int i = 0; i < m; i++) {
    for (int j = 0; j < n; j++) {
    best[i][j] = board[i][j] + max(best[i][j-1], best[i-1][j]);
    }
    }
    glob_max = best[m-1][n-1];
    ค่าที่มากที่สุดของทั้งตารางจะอยู่ที่ช่องสุดท้ายนั่นเอง วิธีนี้มี O(n^2) ซึ่งเร็วกว่าวิธีแรกมาก! 
Views

เข้าสู่ระบบเพื่อแสดงความคิดเห็น

Log in