Cho dải ruy băng chiều dài n, và 3 số a, b, c. Bạn cần tìm số mảnh vải a, b, c mà nó có thể cắt đúng thành dải duy băng n
Input :
5 5 3 2
Ouput :
2
Giải thích : miếng vải b và c lần lượt là 3 và 2, 2 miếng vải này cộng lại đủ thành chiều dài ruy băng chiều dài n
Bài này sử dụng Dynamic Programming, vì giới hạn bài khá nhỏ (1 ≤ n, a, b, c ≤ 4000).
Gọi trạng thái dp[i] là số đoạn tối đa có thể tạo thành tổng i.
- 🔹 Công thức truy hồi : dp[i] = max(dp[i], dp[i - a] + 1)
- 🔹 Để tạo tổng
ihợp lệ:- ✔️ Nếu
dp[i - a]đã được chọn →dp[i - a] ∈ {a, b, c} - ❌ Nếu
dp[i - a]chưa được chọn →dp[i - a] ∉ {a, b, c}
- ✔️ Nếu
Quy trình thực hiện:
- 🟢 Bước 1: Khởi tạo
dpvới giá trị-1(chưa có mảnh vải hợp lệ). - 🟡 Bước 2: Đặt
dp[0] = 0vì không cần chọn bất kỳ đoạn nào. - 🔵 Bước 3: Duyệt qua các giá trị
itừ1 → nđể tính toán tối ưu.
#include <bits/stdc++.h>
using namespace std;
#define mem(a,b) memset(a, b, sizeof(a))
#define all(a) a.begin(), a.end()
#define sz(A) (int) A.size()
#define faster() ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
const int N = 1e5 + 15;
int dp[4004];
void __init__() {mem(dp, -1); dp[0] = 0;}
void solve() {
__init__();
int n, a, b, c;
cin >> n >> a >> b >> c;
for(int i = 1; i <= n; i++) {
if(i >= a && dp[i - a] != -1) dp[i] = max(dp[i], dp[i - a] + 1);
if(i >= b && dp[i - b] != -1) dp[i] = max(dp[i], dp[i - b] + 1);
if(i >= c && dp[i - c] != -1) dp[i] = max(dp[i], dp[i - c] + 1);
}
cout << dp[n] << endl;
}
int main(){
faster()
solve();
return 0;
}