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

Trùm CUỐI 2026-01-08 3:33:12

Link bài tập

1. Phân tích sự khác biệt

  • Ở bài FROG1: Từ tảng đá i , bạn chỉ có thể nhảy đến i+1 hoặc i+2 (tối đa 2 bước).
  • Ở bài FROG2: Từ tảng đá i , bạn có thể nhảy đến bất kỳ tảng đá nào trong khoảng từ i+1 đến i+K (tối đa K bước).

Nhận xét: Thay vì chỉ có 2 sự lựa chọn như trước, bây giờ tại mỗi bước, con ếch có tới K sự lựa chọn. Tuy nhiên, tư duy Quy hoạch động vẫn hoàn toàn áp dụng được.


2. Tư duy thuật toán

Chúng ta vẫn gọi dp[i]chi phí tối thiểu để con ếch nhảy từ tảng đá 1 đến tảng đá i .

  • Trạng thái cơ sở:

    • dp[1] = 0 (Con ếch bắt đầu ở đây).
    • Các vị trí khác khởi tạo bằng một số rất lớn (vô cùng) để lát nữa ta tìm giá trị nhỏ nhất.
  • Công thức truy hồi (Mở rộng): Để đến được tảng đá thứ i , con ếch có thể đã nhảy đến từ một trong các tảng đá trước đó: (i-1), (i-2), ..., (i-K) .

    Với mỗi khoảng cách nhảy j (từ 1 đến K ):

    • Nếu tảng đá (i-j) tồn tại (tức là i-j \ge 1 ):
      • Chi phí = (Chi phí thấp nhất đến i-j ) + (Chi phí nhảy từ i-j sang i ).
      • Công thức: dp[i-j] + |h[i] - h[i-j]|

    => Kết quả dp[i] sẽ là giá trị nhỏ nhất trong tất cả các khả năng nhảy từ K tảng đá phía trước đó.


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

  1. Nhập dữ liệu: Đọc N, K và mảng chiều cao h .
  2. Khởi tạo:
    • Tạo mảng dp kích thước N+1 .
    • Đặt tất cả dp[i] bằng một giá trị rất lớn (ví dụ: 1,000,000,000).
    • Đặt dp[1] = 0.
  3. Tính toán (Dùng 2 vòng lặp lồng nhau):
    • Vòng lặp ngoài: Duyệt từng tảng đá i từ 2 đến N .
    • Vòng lặp trong: Duyệt từng bước nhảy j từ 1 đến K .
      • Kiểm tra nếu (i - j \ge 1) :
        • Cập nhật dp[i] = nhỏ_nhất(dp[i], dp[i-j] + tuyệt_đối(h[i] - h[i-j])).
  4. Kết quả: In ra giá trị dp[N].

4. Biểu diễn bằng Pseudo-code (Mã giả)

Nhập N, K
Nhập mảng h (từ h[1] đến h[N])

Khai báo mảng dp[N+1]
Lấp đầy dp bằng giá trị VÔ_CÙNG
dp[1] = 0

Cho i chạy từ 2 đến N:
    Cho j chạy từ 1 đến K:
        Nếu (i - j >= 1):
            Chi_phí_mới = dp[i-j] + tuyệt_đối(h[i] - h[i-j])
            dp[i] = nhỏ_nhất(dp[i], Chi_phí_mới)

In ra dp[N]

5. Đánh giá độ phức tạp

  • Thời gian: Chúng ta có 2 vòng lặp lồng nhau: vòng ngoài chạy N lần, vòng trong chạy tối đa K lần. Tổng cộng khoảng N \times K phép tính.
  • Với N = 10^5 K = 100 , số phép tính là 10^7 (10 triệu). Máy tính hiện đại có thể xử lý khoảng 10^8 phép tính mỗi giây, nên thuật toán này sẽ chạy rất nhanh (dưới 1 giây).

Lời khuyên: Khi lập trình bài này, hãy đảm bảo giá trị "Vô cùng" bạn chọn đủ lớn để không bị nhỏ hơn kết quả thực tế (với bài này, 10^9 là con số an toàn).