动态规划专题

最长上升子序列:

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;
}
原文地址:https://www.cnblogs.com/SwiftAC/p/12374569.html