DP[1]
Dynamic Programming II
INDEX
LIS
LCS
Bitmask DP
LIS
最長遞增子序列
1. 遞增
2. 子序列
3. DP 做法
遞增
Increasing
子序列
Subsequence
最長遞增子序列
LIS (Longest Increasing Subsequence)
最長遞增子序列
LIS (Longest Increasing Subsequence)
最長遞增子序列
LIS (Longest Increasing Subsequence)
最長遞增子序列
LIS (Longest Increasing Subsequence)
最長遞增子序列
Code
#include <bits/stdc++.h>
using namespace std;
int main() {
int n;
cin >> n;
vector<int> number(n);
for (int i = 0; i < n; i++) {
cin >> number[i];
}
vector<int> dp;
dp.push_back(number[0]);
for (int i = 1; i < n; i++) {
if (number[i] > dp[dp.size() - 1]) {
dp.push_back(number[i]);
}
else {
auto replace = lower_bound(dp.begin(), dp.end(), number[i]);
*replace = number[i];
}
}
cout << dp.size() << '\n';
}
題目
補充,如果要回溯LIS
記錄好前面的數字就可以回溯了
#include <bits/stdc++.h>
using namespace std;
int main() {
int n;
cin >> n;
vector<int> number(n);
for (int i = 0; i < n; i++) {
cin >> number[i];
}
vector<int> dp;
dp.push_back(number[0]);
// 用來記錄每個元素前面值的索引
vector<int> prev(n, -1);
// 用來記錄 dp 中每個元素的索引
vector<int> position(n, -1);
position[0] = 0;
for (int i = 1; i < n; i++) {
int n = number[i];
if (n > dp.back()) {
prev[i] = position[dp.size() - 1]; // 更新前元素索引
dp.push_back(n);
position[dp.size() - 1] = i;
} else {
auto it = lower_bound(dp.begin(), dp.end(), n);
int idx = it - dp.begin();
dp[idx] = n;
position[idx] = i;
if (idx > 0) {
prev[i] = position[idx - 1]; // 更新前元素索引
}
}
}
// 從 dp 中最後一個元素開始回溯 LIS
int idx = position[dp.size() - 1];
vector<int> lis;
while (idx != -1) {
lis.push_back(number[idx]);
idx = prev[idx];
}
// 反轉 LIS 以便從小到大順序
reverse(lis.begin(), lis.end());
// 輸出 LIS 的長度和內容
cout << dp.size() << '\n';
for (int i = 0; i < lis.size(); i++) {
cout << lis[i] << " ";
}
cout << '\n';
}
LCS
最長共同子序列
1. 共同子序列
2. DP 做法
最長共同子序列
LCS (Longest Common Subsequence)
LCS = {b,c,b,a} , {b,c,a,b}
最長共同子序列
LCS (Longest Common Subsequence)
最長共同子序列
LCS (Longest Common Subsequence)
最長共同子序列
LCS (Longest Common Subsequence)
最長共同子序列
LCS (Longest Common Subsequence)
最長共同子序列
LCS (Longest Common Subsequence)
最長共同子序列
LCS (Longest Common Subsequence)
最長共同子序列
LCS (Longest Common Subsequence)
最長共同子序列
LCS (Longest Common Subsequence)
最長共同子序列
LCS (Longest Common Subsequence)
最長共同子序列
LCS (Longest Common Subsequence)
最長共同子序列
LCS (Longest Common Subsequence)
最長共同子序列
LCS (Longest Common Subsequence)
最長共同子序列
LCS (Longest Common Subsequence)
最長共同子序列
LCS (Longest Common Subsequence)
最長共同子序列
LCS (Longest Common Subsequence)
最長共同子序列
LCS (Longest Common Subsequence)
最長共同子序列
LCS (Longest Common Subsequence)
最長共同子序列
Code
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, m;
cin >> n >> m;
string a,b;
cin >> a >> b;
vector<vector<int>> dp(n+1, vector<int>(m+1));
for (int i=0;i<=n;i++) {
dp[i][0] = 0;
}
for (int i=0;i<=m;i++) {
dp[0][i] = 0;
}
for (int i=0;i<n;i++) {
for (int j=0;j<m;j++) {
if (a[i]==b[j]) {
dp[i+1][j+1] = dp[i][j] + 1;
}
else {
dp[i+1][j+1] = max(dp[i][j+1], dp[i+1][j]);
}
}
}
cout << dp[n][m];
}
題目
最長共同子序列 + 回溯 LCS
Code
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, m;
cin >> n >> m;
string a, b;
cin >> a >> b;
vector<vector<int>> dp(n+1, vector<int>(m+1, 0));
vector<vector<int>> prev(n+1, vector<int>(m+1, 0));
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (a[i-1] == b[j-1]) {
dp[i][j] = dp[i-1][j-1] + 1;
prev[i][j] = 0;
} else {
if (dp[i-1][j] > dp[i][j-1]) {
dp[i][j] = dp[i-1][j];
prev[i][j] = 2;
} else {
dp[i][j] = dp[i][j-1];
prev[i][j] = 1;
}
}
}
}
cout << dp[n][m] << '\n';
string lcs = "";
int i = n, j = m;
while (i > 0 && j > 0) {
if (prev[i][j] == 0) {
lcs = a[i-1] + lcs;
i--;
j--;
} else if (prev[i][j] == 1) {
j--;
} else if (prev[i][j] == 2) {
i--;
}
}
cout << lcs << '\n';
return 0;
}
Bitmask DP
位元遮罩
1. Bitmask
2. DP 應用
位元遮罩
Bitmask
Bitmask
代表不同種集合
位元遮罩
Bitmask
位元遮罩
Bitmask
#include <bits/stdc++.h>
using namespace std;
int main() {
for (int i = 0; i < (1 << 8); i++) {
// 從全是 0 跑到 全是 1,也就是跑到 (1 << 8) - 1
for (int j = 0; j < 8; j++) {
if (i & (1 << j)) {
// 如果 j 那格有被取到(1),& 的結果就會 >= 1
// 如果沒有被取到(0),& 的結果就是 0
cout << j << ' ';
}
}
cout << '\n';
}
}
位元遮罩 DP
Bitmask DP
題目
位元遮罩 DP
Bitmask DP
位元遮罩 DP
Bitmask DP
位元遮罩 DP
Bitmask DP
如果他進電梯時會超重,即: last[prev] + W[j] > 重量限制
則加開一台電梯載他,last[i] = w[j],dp[i] = dp[prev] + 1
如果他進電梯時不會超重,
就把它塞進電梯,last[i] = last[prev] + w[j],dp[i] = dp[prev]
對於每個狀態,考慮有搭電梯的每個人,如果他是最後進入電梯的,
答案會更好(次數更小) / 次數一樣但剩餘重量更小
註: prev = i & ~(1 << j),即 i 中但 j 搭電梯前的狀態
#include<bits/stdc++.h>
#define int long long
using namespace std;
signed main() {
int n, x;
cin >> n >> x;
int w[n];
for (int i=0;i<n;i++) {
cin >> w[i];
}
int dp[(1<<n)];
int last[(1<<n)];
dp[0] = 1;
last[0] = 0;
for (int i=1;i<(1<<n);i++) {
dp[i] = 1e9;
last[i] = 1e9;
for (int j=0;j<n;j++) {
if (i & (1<<j)) {
int prev = i ^ (1<<j);
if (last[prev] + w[j] > x) {
if (dp[prev] + 1 < dp[i] || (dp[prev] + 1 == dp[i] && w[j] < last[i])) {
dp[i] = dp[prev] + 1;
last[i] = w[j];
}
} else {
if (dp[prev] < dp[i] || (dp[prev] == dp[i] && last[prev] + w[j] < last[i])) {
dp[i] = dp[prev];
last[i] = last[prev] + w[j];
}
}
}
}
}
cout << dp[(1<<n)-1] << '\n';
}
AC Code
其他題目
掰掰
Dynamic Programming II
By wen Ian
Dynamic Programming II
基礎DP第二堂,上一堂連結請見 source 的那份簡報
- 258