Professional Documents
Culture Documents
Quy Hoạch Động (Dynamic Programing)
Quy Hoạch Động (Dynamic Programing)
Quy Hoạch Động (Dynamic Programing)
Programing)
Quy hoạch động là gì ?
QHĐ là kĩ thuật được được dùng khi có một công thức và một (hoặc một vài) trạng
thái bắt đầu. Một bài toán được tính bởi các bài toán nhỏ hơn đã tìm ra trước
đó. QHĐ có độ phức tạp đa thức nên sẽ chạy nhanh hơn quay lui và duyệt trâu.
2. Lưu trữ các lời giải: Giải quyết từng bài toán con và lưu trữ lời giải vào một
bảng hoặc mảng.
3. Xây dựng lời giải: Sử dụng các lời giải đã lưu trữ để xây dựng lời giải cho bài
toán chính.
4. Tránh dư thừa: Bằng cách lưu trữ các lời giải, quy hoạch động đảm bảo rằng
mỗi bài toán con chỉ được giải một lần, giúp giảm thời gian tính toán.
Tìm đường đi có chi phí tối thiểu từ nút nguồn đến mỗi nút trung gian.
Giải pháp cho bài toán lớn hơn (tìm đường đi có chi phí tối thiểu từ nút nguồn
đến nút đích) có thể được xây dựng từ các giải pháp của những bài toán con
này.
Bắt đầu với lời giải cuối cùng và đệ quy chia nhỏ thành các bài toán con.
Lưu trữ các lời giải của các bài toán con vào một bảng để tránh tính toán
dư thừa.
Phù hợp khi số lượng bài toán con lớn và nhiều trong số chúng được tái sử
dụng.
Bắt đầu với các bài toán con nhỏ nhất và dần dần xây dựng lên lời giải cuối
cùng.
Điền vào một bảng các lời giải cho các bài toán con theo cách từ dưới lên.
Phù hợp khi số lượng bài toán con nhỏ và lời giải tối ưu có thể được tính
trực tiếp từ các lời giải của các bài toán con nhỏ hơn.
#include<bits/stdc++.h>
using namespace std;
int n;
ĐPT: O(2^n)
Đệ quy có nhớ (Memoization)
int n;
vector<int>memo(1000, -1); // bài toán có giá trị -1 là những bà
#include<bits/stdc++.h>
using namespace std;
int n;
vector<int>dp(1000,0);
int main()
{
ios_base::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
n = 6;
//Những bài toán cơ sở
dp[0] = 0;
dp[1] = 1;
//Tính những bài toán lớn hơn từ bài toán những bài toán nhỏ
for(int i = 2; i <= n; i++) dp[i] = dp[i-1] + dp[i-2];
ĐPT: O(n)
Note:
dp là viết tắt của Dynamic Programming
Bài 2: Xâu con chung dài nhất (Longest Common Subsequence _ Link bài)
Duyệt trâu:
#include <bits/stdc++.h>
using namespace std;
string a,b;
Đệ quy có nhớ:
#include <bits/stdc++.h>
using namespace std;
string a, b;
vector<vector<int>> memo(1005, vector<int>(1005, -1));
int lcs(int i, int j)
{
if (i < 0 || j < 0)
return 0;
if (memo[i][j] != -1)
return memo[i][j];
if (a[i] == b[j])
return memo[i][j] = 1 + lcs(i - 1, j - 1);
else
return memo[i][j] = max(lcs(i - 1, j), lcs(i, j - 1));
}
void solve()
{
cin >> a >> b;
cout << lcs(a.size() - 1, b.size() - 1);
}
int main()
{
ios_base::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
solve();
}
Duyệt:
string a, b;
vector<vector<int>> dp(1005, vector<int>(1005, 0));
void solve()
{
cin >> a >> b;
int n = a.size();
int m = b.size();
a = " " + a;
b = " " + b;
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
if (a[i] == b[j]) dp[i][j] = dp[i-1][j-1]+1;
else dp[i][j] = max(dp[i-1][j],dp[i][j-1]);
}
}
cout << dp[n][m];
}
int main()
{
ios_base::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
solve();
}
Bài 3: Dãy còn tăng dài nhất (Longest Increasing Subsequence _ Link bài)
Duyệt trâu:
int a[1005];
int n;
const int inf = 1e9 + 7;
Đệ quy có nhớ:
#include <bits/stdc++.h>
using namespace std;
int a[1005];
int n;
Duyệt
#include <bits/stdc++.h>
using namespace std;
void solve()
{
cin >> n;
for (int i = 0; i < n; i++)
cin >> a[i];
a[n] = inf;
int res = 0;
for(int i = 0; i <= n; i++){
res = 0;
for(int j = 0; j < i; j++){
if (a[j] <= a[i]) res = max(res,dp[j] + 1);
}
dp[i] = res;
}
cout << dp[n];
}
signed main()
{
ios_base::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
solve();
}