Hướng dẫn thuật toán

Trùm CUỐI 2026-01-11 11:18:04

Link bài tập

1. Phân tích đề bài

  • Đặc điểm: Đây là bài toán Cái túi (Knapsack) dạng 0/1.
  • Ràng buộc đáng chú ý:
    • Số lượng vật N nhỏ ( \le 100 ).
    • Trọng lượng túi W và trọng lượng vật w_i rất lớn (lên đến 10^9 ).
    • Giá trị vật v_i khá nhỏ ( \le 1000 ).
  • Vấn đề: Nếu dùng phương pháp Quy hoạch động (QHĐ) truyền thống với trạng thái là trọng lượng DP[w] (giá trị lớn nhất với trọng lượng w ), mảng sẽ không thể chứa nổi chỉ số 10^9 .
  • Giải pháp: Thay vì tính giá trị lớn nhất theo trọng lượng, ta sẽ tính trọng lượng nhỏ nhất để đạt được một giá trị v nhất định.

2. Ý tưởng thuật toán

  • Tổng giá trị tối đa tất cả các vật có thể đạt được là: V_{max} = N \times \max(v_i) = 100 \times 1000 = 100,000 .
  • Gọi DP[v] trọng lượng tổng nhỏ nhất để đạt được tổng giá trị đúng bằng v .
  • Mục tiêu: Tìm giá trị v lớn nhất sao cho DP[v] \le W .

3. Các bước thực hiện

  1. Khởi tạo:
    • Tạo mảng DP có kích thước V_{max} + 1 .
    • Đặt DP[0] = 0 (trọng lượng để có giá trị 0 là bằng 0).
    • Tất cả các vị trí còn lại DP[v] đặt bằng một giá trị vô cùng lớn ( \infty ).
  2. Duyệt các vật: Với mỗi vật thứ i có trọng lượng w_i và giá trị v_i :
    • Duyệt ngược biến j từ V_{max} xuống v_i (để tránh dùng một vật nhiều lần):
    • Cập nhật: DP[j] = \min(DP[j], DP[j - v_i] + w_i) .
  3. Tìm kết quả:
    • Duyệt từ j = V_{max} ngược về 0 .
    • Giá trị j đầu tiên thỏa mãn DP[j] \le W chính là đáp án cần tìm.

4. Lưu ý khi triển khai

  • Kiểu dữ liệu: Trọng lượng W w_i có thể lên đến 10^9 , do đó mảng DP và các biến liên quan đến trọng lượng phải dùng kiểu số nguyên 64-bit (ví dụ: long long trong C++ hoặc số nguyên mặc định trong Python).
  • Giá trị vô cùng: Chọn một hằng số \infty đủ lớn (lớn hơn tổng tất cả w_i có thể có, ví dụ 10^{14} hoặc hơn).
  • Tối ưu: Chỉ cần duyệt đến tổng giá trị thực tế của các vật đang có thay vì luôn duyệt đến 100,000 .