动态规划专题
最长上升子序列:
dp = [1 for i in range(1007)]
n = eval(input())
a = list(map(int, input().split()))
for i in range(n):
for j in range(0, i):
if a[j] <= a[i]:
dp[i] = max(dp[i], dp[j] + 1)
print(max(dp))
最长公共子序列:
s1 = input() s2 = input() n = len(s1) m = len(s2) dp = [[0 for j in range(m + 1)] for i in range(n + 1)] for i in range(n): for j in range(m): if s1[i] == s2[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]) print(max(max(dp)))
二进制优化多重背包:
#include<bits/stdc++.h> using namespace std; const int maxn = 1e3 + 7; int vv[maxn], ww[maxn], s[maxn], N, V, v[maxn]; int dp[maxn], w[maxn]; int get(int x) { int p = 0, tot = 0; for (int i = 0; ; i++) { tot += pow(2, i); if (tot <= x) { p = i; } if (tot >= x) break; } return p; } int main() { int cnt = 0; cin >> N >> V; for (int i = 0; i < N; i++) { cin >> vv[i] >> ww[i] >> s[i]; } for (int i = 0; i < N; i++) { int p = get(s[i]); int R = s[i] - pow(2, p + 1) + 1; for (int j = 0; j <= p; j++) { v[++cnt] = pow(2, j) * vv[i], w[cnt] = ww[i] * pow(2, j); } if (R) v[++cnt] = R * vv[i], w[cnt] = ww[i] * R; } for (int i = 1; i <= cnt; i++) { for (int j = V; j >= v[i]; j--) { dp[j] = max(dp[j], dp[j - v[i]] + w[i]); } } cout << *max_element(dp, dp + 1 + V) << endl; return 0; }
多重背包判断能否组成问题:
#include<bits/stdc++.h> using namespace std; const int maxn = 1e2 + 7; int A[maxn], C[maxn]; bool dp[maxn * 1000]; int used[maxn * 1000]; int main() { int N, M; while (cin >> N >> M && N && M) { memset(dp, false, sizeof(dp)); for (int i = 1; i <= N; i++) cin >> A[i]; for (int i = 1; i <= N; i++) cin >> C[i]; dp[0] = true; for (int i = 1; i <= N; i++) { memset(used, 0, sizeof(used)); for (int j = A[i]; j <= M; j++) { if (!dp[j] && dp[j - A[i]] && used[j - A[i]] + 1 <= C[i]) dp[j] = true, used[j] = used[j - A[i]] + 1; } } int res = 0; for (int i = 1; i <= M; i++) { res += dp[i]; } cout << res << endl; } return 0; }
分组背包问题:
#include<bits/stdc++.h> using namespace std; const int maxn = 1e2 + 7; int N, V, s[maxn], v[maxn][maxn], w[maxn][maxn], dp[maxn]; int main() { cin >> N >> V; for (int i = 1; i <= N; i++) { cin >> s[i]; for (int j = 1; j <= s[i]; j++) cin >> v[i][j] >> w[i][j]; } for (int i = 1; i <= N; i++) { for (int j = V; j >= 0; j--) { for (int k = 1; k <= s[i]; k++) { if (j >= v[i][k]) dp[j] = max(dp[j - v[i][k]] + w[i][k], dp[j]); } } } cout << *max_element(dp, dp + 1 + V) << endl; return 0; }
区间dp问题:
#include<bits/stdc++.h> using namespace std; const int maxn = 3e2 + 7; int dp[maxn][maxn], a[maxn], sum[maxn], N; int main() { cin >> N; memset(dp, 0x3f, sizeof(dp)); for (int i = 1; i <= N; i++) { cin >> a[i]; sum[i] = sum[i - 1] + a[i]; dp[i][i] = 0; } for (int len = 2; len <= N; len++) { for (int l = 1; l <= N - len + 1; l++) { int r = l + len - 1; for (int k = l; k < r; k++) dp[l][r] = min(dp[l][r], dp[l][k] + dp[k + 1][r]); dp[l][r] += sum[r] - sum[l - 1]; } } cout << dp[1][N] << endl; return 0; }
树形dp入门:
#include<bits/stdc++.h> using namespace std; const int maxn = 6e3 + 7; vector<int> G[maxn]; int dp[maxn][2], h[maxn], in[maxn]; void Dp(int u) { dp[u][0] = 0; dp[u][1] = h[u]; for (int i = 0; i < G[u].size(); i++) { int v = G[u][i]; Dp(v); dp[u][0] += max(dp[v][1], dp[v][0]); dp[u][1] += dp[v][0]; } } int main() { int n, u, v; cin >> n; for (int i = 1; i <= n; i++) cin >> h[i]; for (int i = 1; i < n; i++) { cin >> v >> u; G[u].push_back(v); in[v]++; } int root = -1; for (int i = 1; i <= n; i++) { if (!in[i]) root = i; } Dp(root); cout << max(dp[root][0], dp[root][1]) << endl; return 0; }
ST算法:
#include<bits/stdc++.h> using namespace std; const int maxn = 2e5 + 7; const int maxm = 32; int dp[maxn][maxm], n, a[maxn]; void ST_work() { for (int i = 1; i <= n; i++) dp[i][0] = a[i]; int t = log(n) / log(2) + 1; for (int j = 1; j < t; j++) { for (int i = 1; i <= n - (1 << j) + 1; i++) { dp[i][j] = max(dp[i][j - 1], dp[i + (1 << (j - 1))][j - 1]); } } } int ST_query(int l, int r) { int t = log(r - l + 1) / log(2); return max(dp[l][t], dp[r - (1 << t) + 1][t]); } void init() { cin >> n; for (int i = 1; i <= n; i++) cin >> a[i]; ST_work(); } void query() { int m, l, r; cin >> m; while (m--) { cin >> l >> r; cout << ST_query(l, r) << endl; } } int main() { init(); query(); return 0; }
最大上升子序列:
#include<bits/stdc++.h> using namespace std; const int maxn = 1e5 + 7; const int inf = 0x3f3f3f3f; int a[maxn], dp[maxn], n; int main() { cin >> n; for (int i = 1; i <= n; i++) cin >> a[i]; fill(dp, dp + maxn, inf); for (int i = 1; i <= n; i++) { *upper_bound(dp + 1, dp + 1 + n, a[i]) = a[i]; } cout << lower_bound(dp + 1, dp + 1 + n, inf) - dp - 1 << endl; return 0; }