ข้อนี้มี Sushi ยาว ที่สามารถตัดได้ที่ ตำแหน่ง คือที่ระยะ จากด้านซ้าย โดยจะแบ่งให้เพื่อน คน คนละหนึ่งชิ้นหลังตัด โดยคนที่ จะได้รับส่วนที่ จากด้านซ้ายเรียงกันหลังการตัด
เพื่อนคนที่ มีค่าความชอบ และจะได้รับความสุขเป็น คูณความยาวของชิ้นที่ได้รับ (ต้องได้ชิ้นที่มีความยาวมากกว่า )
โจทย์ถามว่าจะได้ความสุขรวมมากที่สุดเท่าไหร่
Dynamic Programming
เพื่อความสะดวกกำหนดให้
ข้อนนี้สามารถมองเป็นโจทย์ Dynamic Programming โดยให้ แทนค่ารวมมากสุดที่เป็นไปได้หากแบ่ง Sushi แล้วถึง โดยคนที่ได้รับชิ้น คือเพื่อนที่
เราจะเริ่มจาก เพราะยังไม่มีความสุขและยังไม่ได้ให้ Sushi ชิ้นใดกับเพื่อนคนไหน และ เพราะไม่สามารถจบที่เพื่อนคนที่ โดยยังไม่มีใครได้สักชิ้น
จากนั้นสามารถพิจารณากรณี
สังเกตว่า จะเท่ากับ เพราะเพื่อนถ้าคนแรกได้ถึง จะต้องได้ทั้งหมดตั้งแต่ ถึง
สำหรับ จะสังเกตว่า เพราะถ้าจะจบการแบ่งถึง โดยให้เพื่อนคนที่ ชิ้นก่อนหน้าถึง จะต้องถูกแบ่งให้เพื่อนคนที่ หรือ เท่านั้น ซึ่งจะเป็น และการให้ช่วง กับคนที่ จะได้ความสุข
เห็นได้ว่าการคำนวณแต่ละช่องของ จะใช้เวลา มี ช่องทั้งหมดจึงเป็น
อย่างไรก็ตามเนื่องจากข้อนี้ให้ Memory เพียง 16 Mb จะไม่สามารถประกาศ ให้มี ช่องโดยตรงจึงต้องหาวิธีลดการใช้ Memory
สังเกตว่าในการคำนวณ สำหรับ ใดๆ เราจะต้องใช้เพียง Array เพราะในสูตรที่ใช้จะใช้เพียง โดยไม่ต้องใช้ ดังนั้น ณ เวลาใดๆ จะต้องเก็บอย่างมาก ค่า ทำให้ลดการใช้ Memory เป็น โดยไม่เพิ่ม Time Complexity
ตัวอย่างโค้ด
#include <iostream> using namespace std; int R[20010]; int P[20010]; int DP[2][20010]; int main() { int n, m, k; cin >> n >> m >> k; for (int i = 1; i <= m; i++) cin >> R[i]; R[m + 1] = n; for (int i = 1; i <= k; i++) cin >> P[i]; DP[0][0] = 0; for (int i = 1; i <= m; i++) DP[0][i] = -1000000000; for (int i = 1; i <= m + 1; i++) { DP[i % 2][1] = R[i] * P[1]; for (int j = 2; j <= k; j++) DP[i % 2][j] = max(DP[(i + 1) % 2][j], DP[(i + 1) % 2][j - 1]) + (R[i] - R[i - 1]) * P[j]; } cout << DP[(m + 1) % 2][k]; }
ในโค้ดนี้จะใช้ DP[0] กับ DP[1] สลับกันโดย DP[i%2] จะใช้แทน ในแต่ละขั้น และ DP[(i+1)%2] จะแทน