记忆化搜索
int dfs(int pos, int tleft)
{
if (f[pos][tleft] != -1)
return f[pos][tleft];
if (pos == m + 1)
return f[pos][tleft] = 0;
int dfs1, dfs2 = -INF;
dfs1 = dfs(pos + 1, tleft);
if (tleft >= tcost[pos])
dfs2 = dfs(pos + 1, tleft - tcost[pos]) + mget[pos];
return f[pos][tleft] = max(dfs1, dfs2);
}
int main()
{
memset(f, -1, sizeof(f));
cin >> t >> m;
for (int i = 1; i <= m; i++)
{
cin >> tcost[i] >> mget[i];
}
cout << dfs(1, t) << endl;
return 0;
}
背包
01 背包
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; i++)
{
cin >> w[i] >> d[i];
}
for (int i = 1; i <= n; i++)
{
for (int j = m; j >= w[i]; j--)
{
f[j] = max(f[j], f[j - w[i]] + d[i]);
}
}
cout << f[m];
return 0;
}
完全背包
int main()
{
cin >> t >> m;
for (int i = 1; i <= m; i++)
{
cin >> a[i] >> b[i];
}
for (int i = 1; i <= m; i++)
{
for (int j = a[i]; j <= t; j++)
{
f[j] = max(f[j], f[j - a[i]] + b[i]);
}
}
cout << f[t];
return 0;
}
多重背包
二进制分组优化
index=0;
for (int i = 1; i <= n; i++)
{
int c = 1, p, h, k;
cin >> p >> h >> k;
while (k - c)
{
k -= c;
list[++index].w = c * p;
list[index].v = c * h;
c *= 2;
}
list[++index].w = k * p;
list[index].v = k * h;
}
单调队列/单调栈优化
#include <algorithm>
#include <cstring>
#include <iostream>
using namespace std;
typedef long long ll;
const int maxn = 150000 + 10;
const int maxm = 300 + 10;
ll f[2][maxn];
ll a[maxn], b[maxm], t[maxn];
int n, m, d;
int que[maxn];
int fl = 1;
void init()
{
memset(f, 207, sizeof(f));
memset(que, 0, sizeof(que));
for (int i = 1; i <= n; i++)
f[0][i] = 0;
fl = 1;
}
void dp()
{
init();
for (int i = 1; i <= m; i++)
{
int l = 1, r = 0, k = 1;
for (int j = 1; j <= n; j++)
{ //在这里使用了单调队列的优化
for (; k <= min(1ll * n, j + d * (t[i] - t[i - 1])); k++)
{
while (l <= r && f[fl ^ 1][que[r]] <= f[fl ^ 1][k])
r--;
que[++r] = k;
}
while (l <= r && que[l] < max(1ll, j - d * (t[i] - t[i - 1])))
l++;
f[fl][j] = f[fl ^ 1][que[l]] - abs(a[i] - j) + b[i];
}
fl ^= 1;
}
}
int main()
{
cin >> n >> m >> d;
for (int i = 1; i <= m; i++)
cin >> a[i] >> b[i] >> t[i];
dp();
ll ans = -1e18;
for (int i = 1; i <= n; i++)
ans = max(ans, f[fl ^ 1][i]);
cout << ans << endl;
return 0;
}
二维费用背包
for (int k = 1; k <= n; k++)
{
for (int i = m; i >= mi; i--)
for (int j = t; j >= ti; j--)
dp[i][j] = max(dp[i][j], dp[i - mi][j - ti] + 1);
}
分组背包
for (int k = 1; j <= ts; k++)
for (int i = m; i >= 0; i--)
for (int j = 1; j <= cnt[k]; j++)
if (i >= w[t[k][j]])
dp[i] = max(dp[i], dp[i - w[t[k][j]]] + c[k][j]);
区间 DP
for (len = 1; len <= n; len++)
for (i = 1; i <= 2 * n - 1; i++)
{
int j = len + i - 1;
for (k = 1; k < j && k <= 2 * n - 1; k++)
f[i][j] = max(f[i][j], f[i][k] + f[k + 1][j] + sum[j] - sum[i - 1]);
}
DAG 上的 DP
#include <cmath>
#include <cstring>
#include <iostream>
using namespace std;
#define MAXN (30 + 5)
#define MAXV (500 + 5)
int d[MAXN][3];
int x[MAXN], y[MAXN], z[MAXN];
int babylon_sub(int c, int rot, int n)
{
if (d[c][rot] != -1)
{
return d[c][rot];
}
d[c][rot] = 0;
int base1, base2;
if (rot == 0)
{
base1 = x[c];
base2 = y[c];
}
if (rot == 1)
{
base1 = y[c];
base2 = z[c];
}
if (rot == 2)
{
base1 = x[c];
base2 = z[c];
}
for (int i = 0; i < n; i++)
{ //根据不同条件,分别调用不同的递归
if ((x[i] < base1 && y[i] < base2) || (y[i] < base1 && x[i] < base2))
d[c][rot] = max(d[c][rot], babylon_sub(i, 0, n) + z[i]);
if ((y[i] < base1 && z[i] < base2) || (z[i] < base1 && y[i] < base2))
d[c][rot] = max(d[c][rot], babylon_sub(i, 1, n) + x[i]);
if ((x[i] < base1 && z[i] < base2) || (z[i] < base1 && x[i] < base2))
d[c][rot] = max(d[c][rot], babylon_sub(i, 2, n) + y[i]);
}
return d[c][rot];
}
int babylon(int n)
{
for (int i = 0; i < n; i++)
{
d[i][0] = -1;
d[i][1] = -1;
d[i][2] = -1;
}
int r = 0;
for (int i = 0; i < n; i++)
{ //三种建法
r = max(r, babylon_sub(i, 0, n) + z[i]);
r = max(r, babylon_sub(i, 1, n) + x[i]);
r = max(r, babylon_sub(i, 2, n) + y[i]);
}
return r;
}
int main()
{
int t = 0;
while (1)
{
int n;
cin >> n;
if (n == 0)
break;
t++;
for (int i = 0; i < n; i++)
{
cin >> x[i] >> y[i] >> z[i];
}
cout << "Case " << t << ":"
<< " maximum height = " << babylon(n); //递归
cout << endl;
}
return 0;
}
状压 DP
#include <algorithm>
#include <iostream>
using namespace std;
long long sta[2005], sit[2005], f[15][2005][105];
int n, k, cnt;
void dfs(int x, int num, int cur)
{
if (cur >= n)
{ //有新的合法状态
sit[++cnt] = x;
sta[cnt] = num;
return;
}
dfs(x, num, cur + 1); //cur位置不放国王
dfs(x + (1 << cur), num + 1, cur + 2); //cur位置放国王,与它相邻的位置不能再放国王
}
bool compatible(int j, int x)
{
if (sit[j] & sit[x])
return false;
if ((sit[j] << 1) & sit[x])
return false;
if (sit[j] & (sit[x] << 1))
return false;
return true;
}
int main()
{
cin >> n >> k;
dfs(0, 0, 0); //先预处理一行的所有合法状态
for (int j = 1; j <= cnt; j++)
f[1][j][sta[j]] = 1;
for (int i = 2; i <= n; i++)
for (int j = 1; j <= cnt; j++)
for (int x = 1; x <= cnt; x++)
{
if (!compatible(j, x))
continue;
for (int l = sta[j]; l <= k; l++)
f[i][j][l] += f[i - 1][x][l - sta[j]];
}
long long ans = 0;
for (int i = 1; i <= cnt; i++)
ans += f[n][i][k]; //累加答案
cout << ans << endl;
return 0;
}
数位 DP
#include <bits/stdc++.h>
using namespace std;
const int N = 15;
typedef long long ll;
ll l, r, dp[N], sum[N], mi[N];
ll ans1[N], ans2[N];
int a[N];
inline void solve(ll n, ll *ans) {
ll tmp = n;
int len = 0;
while (n) a[++len] = n % 10, n /= 10;
for (int i = len; i >= 1; --i) {
for (int j = 0; j < 10; j++) ans[j] += dp[i - 1] * a[i];
for (int j = 0; j < a[i]; j++) ans[j] += mi[i - 1];
tmp -= mi[i - 1] * a[i], ans[a[i]] += tmp + 1;
ans[0] -= mi[i - 1];
}
}
int main() {
scanf("%lld%lld", &l, &r);
mi[0] = 1ll;
for (int i = 1; i <= 13; ++i) {
dp[i] = dp[i - 1] * 10 + mi[i - 1];
mi[i] = 10ll * mi[i - 1];
}
solve(r, ans1), solve(l - 1, ans2);
for (int i = 0; i < 10; ++i) printf("%lld ", ans1[i] - ans2[i]);
return 0;
}