动态规划
数字三角形模型
最低通行费
#include <bits/stdc++.h>
using namespace std;
const int N = 105, inf = 0x3f3f3f3f;
int dp[N][N], a[N][N], r, c, T;
int main()
{
scanf("%d", &r);
c = r;
for (int i = 1; i <= r; ++ i)
{
for (int j = 1; j <= c; ++ j) scanf("%d", &a[i][j]);
}
memset(dp, 0x3f, sizeof dp);
dp[0][1] = dp[1][0] = 0;
for (int i = 1; i <= r; ++ i)
{
for (int j = 1; j <= c; ++ j)
{
dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + a[i][j];
}
}
printf("%d\n", dp[r][c]);
return 0;
}
方格取数
#include <bits/stdc++.h>
using namespace std;
const int N = 12;
int n, dp[N + N][N][N];
int a[N][N];
int main()
{
scanf("%d", &n);
while(true)
{
int x, y, w;
scanf("%d %d %d", &x, &y, &w);
if(!x && !y && !w) break;
a[x][y] = w;
}
for (int k = 2; k <= n + n; ++ k)
{
for (int i1 = max(1, k - n); i1 <= n && i1 <= k - 1; ++ i1)
{
for (int i2 = max(1, k - n); i2 <= n && i2 <= k - 1; ++ i2)
{
if(i1 == i2)
{
dp[k][i1][i2] = max(dp[k - 1][i1][i2], max(dp[k - 1][i1][i2 - 1], max(dp[k - 1][i1 - 1][i2], dp[k - 1][i1 - 1][i2 - 1]))) + a[i1][k - i1];
}
else
{
dp[k][i1][i2] = max(dp[k - 1][i1][i2], max(dp[k - 1][i1][i2 - 1], max(dp[k - 1][i1 - 1][i2], dp[k - 1][i1 - 1][i2 - 1]))) + a[i1][k - i1] + a[i2][k - i2];
}
}
}
}
printf("%d", dp[n + n][n][n]);
return 0;
}
传纸条
#include <bits/stdc++.h>
using namespace std;
const int N = 52, inf = 0x3f3f3f3f;
int n, dp[N + N][N][N], m;
int a[N][N];
int main()
{
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; ++ i)
{
for (int j = 1; j <= m; ++ j) scanf("%d", &a[i][j]);
}
for (int k = 2; k <= n + m; ++ k)
{
for (int i1 = max(1, k - m); i1 <= n && i1 <= k - 1; ++ i1)
{
for (int i2 = max(1, k - m); i2 <= n && i2 <= k - 1; ++ i2)
{
if(i1 != i2 || k == 2 || k == n + m)
{
dp[k][i1][i2] = max(dp[k - 1][i1 - 1][i2 - 1], max(dp[k - 1][i1][i2], max(dp[k - 1][i1][i2 - 1], dp[k - 1][i1 - 1][i2]))) + a[i1][k - i1] + a[i2][k - i2];
}
else dp[k][i1][i2] = -inf;
}
}
}
printf("%d", dp[n + m][n][n]);
return 0;
}
最长上升子序列
怪盗基德的滑翔翼
#include <bits/stdc++.h>
using namespace std;
const int N = 105;
int T, dp[N], h[N], a[N];
int main()
{
scanf("%d", &T);
while(T --)
{
int n;
scanf("%d", &n);
for (int i = 1; i <= n; ++ i) dp[i] = 0, scanf("%d", &h[i]);
int ans = 0;
for (int i = 1; i <= n; ++ i)
{
dp[i] = 1;
for (int j = 1; j <= i - 1; ++ j)
{
if(h[i] < h[j]) dp[i] = max(dp[i], dp[j] + 1);
}
ans = max(ans, dp[i]);
}
for (int i = 1; i <= n; ++ i) dp[i] = 0;
for (int i = 1; i <= n; ++ i) a[i] = h[n - i + 1];
for (int i = 1; i <= n; ++ i)
{
dp[i] = 1;
for (int j = 1; j <= i - 1; ++ j)
{
if(a[i] < a[j]) dp[i] = max(dp[i], dp[j] + 1);
}
ans = max(ans, dp[i]);
}
printf("%d\n", ans);
}
return 0;
}
登山
#include <bits/stdc++.h>
using namespace std;
const int N = 1005;
int dp1[N], a[N], dp2[N], n;
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; ++ i) scanf("%d", &a[i]), dp1[i] = 1, dp2[i] = 1;
for (int i = 1; i <= n; ++ i)
{
for (int j = 1; j <= i - 1; ++ j)
{
if(a[i] > a[j]) dp1[i] = max(dp1[i], dp1[j] + 1);
}
}
for (int i = n; i >= 1; -- i)
{
for (int j = n; j >= i + 1; -- j)
{
if(a[i] > a[j]) dp2[i] = max(dp2[i], dp2[j] + 1);
}
}
int ans = 0;
for (int i = 1; i <= n; ++ i)
{
ans = max(ans, dp1[i] + dp2[i] - 1);
}
printf("%d", ans);
}
合唱队形
#include <bits/stdc++.h>
using namespace std;
const int N = 1005;
int dp1[N], a[N], dp2[N], n;
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; ++ i) scanf("%d", &a[i]), dp1[i] = 1, dp2[i] = 1;
for (int i = 1; i <= n; ++ i)
{
for (int j = 1; j <= i - 1; ++ j)
{
if(a[i] > a[j]) dp1[i] = max(dp1[i], dp1[j] + 1);
}
}
for (int i = n; i >= 1; -- i)
{
for (int j = n; j >= i + 1; -- j)
{
if(a[i] > a[j]) dp2[i] = max(dp2[i], dp2[j] + 1);
}
}
int ans = 0;
for (int i = 1; i <= n; ++ i)
{
ans = max(ans, dp1[i] + dp2[i] - 1);
}
printf("%d", n - ans);
}
友好城市
#include <bits/stdc++.h>
using namespace std;
const int N = 1000005;
#define x first
#define y second
pair<int, int> p[N];
int n, dp[N], ans = 0, bit[N], tot;
int lowbit(int &x)
{
return x & (-x);
}
void update(int x, int k)
{
for (int i = x; i <= tot; i += lowbit(i)) bit[i] = max(bit[i], k);
return ;
}
int query(int x)
{
int ans = 0;
for (int i = x; i >= 1; i -= lowbit(i)) ans = max(ans, bit[i]);
return ans;
}
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; ++ i) scanf("%d %d", &p[i].first, &p[i].second), tot = max(tot, p[i].y);
sort(p + 1, p + n + 1);
tot = max(tot, p[1].x);
for (int i = 1; i <= n; ++ i)
{
dp[i] = query(p[i].y) + 1;
update(p[i].y, dp[i]);
ans = max(ans, dp[i]);
}
printf("%d", ans);
return 0;
}
最大上升子序列和
#include <bits/stdc++.h>
using namespace std;
const int N = 1005;
int n, a[N], dp[N], ans = 0;
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; ++ i) scanf("%d", &a[i]);
for (int i = 1; i <= n; ++ i)
{
dp[i] = a[i];
for (int j = 1; j <= i - 1; ++ j)
{
if(a[j] < a[i] && dp[i] < dp[j] + a[i]) dp[i] = dp[j] + a[i];
}
ans = max(ans, dp[i]);
}
printf("%d", ans);
return 0;
}
拦截导弹
#include <bits/stdc++.h>
using namespace std;
const int N = 200005;
int b[N], dp[N], bit[N], a[N];
int tot = 0, n;
int lowbit(int i)
{
return i & (-i);
}
void update(int x, int k)
{
for (int i = x; i <= n; i += lowbit(i)) bit[i] = max(bit[i], k);
return ;
}
int query(int x)
{
int ans = 0;
for (int i = x; i >= 1; i -= lowbit(i)) ans = max(ans, bit[i]);
return ans;
}
int main()
{
while(scanf("%d", &a[n + 1]) != EOF) { n ++;}
for (int i = 1; i <= n; ++ i) b[i] = a[i];
sort(b + 1, b + n + 1);
tot = unique(b + 1, b + n + 1) - b - 1;
int ans = 0;
for (int i = 1; i <= n; ++ i)
{
a[i] = lower_bound(b + 1, b + tot + 1, a[i]) - b;
a[i] = n - a[i] + 1;
}
for (int i = 1; i <= n; ++ i)
{
dp[i] = query(a[i]) + 1;
update(a[i], dp[i]);
ans = max(ans, dp[i]);
a[i] = n - a[i] + 1;
}
tot = 1, b[1] = a[1];
for (int i = 2; i <= n; ++ i)
{
if(a[i] > b[tot]) b[++ tot] = a[i];
else
{
int l = 0, r = tot, mid, pos = 0;
while(l <= r)
{
mid = (l + r) >> 1;
if(a[i] <= b[mid]) r = mid - 1, pos = mid;
else l = mid + 1;
}
b[pos] = a[i];
}
}
printf("%d\n%d", ans, tot);
}
导弹防御系统
#include <bits/stdc++.h>
using namespace std;
const int N = 55;
int a[N], u[N], d[N], ans, n;
void dfs(int x, int su, int sd)
{
if(su + sd >= ans) return ;
if(x == n + 1)
{
ans = su + sd;
return ;
}
int pos = su + 1;
for (int i = 1; i <= su; ++ i)
{
if(a[x] >= u[i]) {pos = i; break; }
}
int t = u[pos];
u[pos] = a[x];
if(pos == su + 1) dfs(x + 1, su + 1, sd);
else dfs(x + 1, su, sd);
u[pos] = t;
pos = sd + 1;
for (int i = 1; i <= sd; ++ i)
{
if(a[x] <= d[i]) {pos = i; break; }
}
t = d[pos];
d[pos] = a[x];
if(pos == sd + 1) dfs(x + 1, su, sd + 1);
else dfs(x + 1, su, sd);
d[pos] = t;
return ;
}
int main()
{
while(scanf("%d", &n) != EOF)
{
if(n == 0) break;
for (int i = 1; i <= n; ++ i) scanf("%d", &a[i]);
ans = n;
dfs(1, 0, 0);
printf("%d\n", ans);
}
return 0;
}
最长公共上升子序列
#include <bits/stdc++.h>
using namespace std;
const int N = 3005;
int n, dp[N][N], maxv = 0;
int a[N], b[N];
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; ++ i) scanf("%d", &a[i]);
for (int i = 1; i <= n; ++ i) scanf("%d", &b[i]);
for (int i = 1; i <= n; ++ i)
{
maxv = 0;
for (int j = 1; j <= n; ++ j)
{
dp[i][j] = dp[i - 1][j];
if(a[i] == b[j])
{
dp[i][j] = max(1, maxv + 1);
// for (int k = 1; k <= j - 1; ++ k)
// {
// if(b[k] < b[j]) dp[i][j] = max(dp[i][j], dp[i - 1][k] + 1);
// }
}
if(b[j] < a[i]) maxv = max(maxv, dp[i][j]);
}
}
int ans = 0;
for (int i = 1; i <= n; ++ i) ans = max(ans, dp[n][i]);
printf("%d", ans);
return 0;
}
背包模型
采药(01背包)
#include <bits/stdc++.h>
using namespace std;
const int N = 1005;
int dp[N], T, m, t, w;
int main()
{
scanf("%d %d", &T, &m);
for (int i = 1; i <= m; ++ i)
{
scanf("%d %d", &t, &w);
for (int j = T; j >= w; -- j)
{
dp[j] = max(dp[j], dp[j - t] + w);
}
}
printf("%d", dp[T]);
return 0;
}
装箱问题(01背包)
#include <bits/stdc++.h>
using namespace std;
const int N = 20005;
int dp[N], T, m, t, w;
int main()
{
scanf("%d %d", &T, &m);
for (int i = 1; i <= m; ++ i)
{
scanf("%d", &t);
w = t;
for (int j = T; j >= w; -- j)
{
dp[j] = max(dp[j], dp[j - t] + w);
}
}
printf("%d", T - dp[T]);
return 0;
}
宠物小精灵之收服
#include <bits/stdc++.h>
using namespace std;
int dp[1005][505];
int n, m, k;
int main()
{
scanf("%d %d %d", &n, &m, &k);
for (int i = 1; i <= k; ++ i)
{
int g, e;
scanf("%d %d", &g, &e);
for (int x = n; x >= g; -- x)
{
for (int y = m; y >= e; -- y)
{
dp[x][y] = max(dp[x][y], dp[x - g][y - e] + 1);
}
}
}
int val;
if(dp[n][m] == dp[n][m - 1]) val = dp[n][m];
else val = dp[n][m - 1];
for (int y = 0; y <= m; ++ y)
{
if(val == dp[n][y])
{
printf("%d %d", val, m - y);
break;
}
}
return 0;
}
数字组合
#include <bits/stdc++.h>
using namespace std;
int dp[10005], n, m;
int main()
{
scanf("%d %d", &n, &m);
dp[0] = 1;
for (int i = 1; i <= n; ++ i)
{
int w;
scanf("%d", &w);
for (int j = m; j >= w; -- j) dp[j] += dp[j - w];
}
printf("%d", dp[m]);
return 0;
}
买书
#include <bits/stdc++.h>
using namespace std;
int dp[10005], m, w[5];
int main()
{
scanf("%d", &m);
dp[0] = 1;
w[1] = 10, w[2] = 20, w[3] = 50, w[4] = 100;
for (int i = 1; i <= 4; ++ i)
{
for (int j = w[i]; j <= m; ++ j) dp[j] += dp[j - w[i]];
}
printf("%d", dp[m]);
return 0;
}
货币系统
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n, m;
ll dp[3005];
int main()
{
scanf("%d %d", &n, &m);
dp[0] = 1ll;
for (int i = 1; i <= n; ++ i)
{
int w;
scanf("%d", &w);
for (int j = w; j <= m; ++ j) dp[j] += dp[j - w];
}
printf("%lld", dp[m]);
return 0;
}
货币系统
#include <bits/stdc++.h>
using namespace std;
const int N = 25005;
int dp[N], a[N], n, T;
int main()
{
dp[0] = 1;
scanf("%d", &T);
while(T --)
{
scanf("%d", &n);
int tot = 0;
for (int i = 1; i <= n; ++ i) scanf("%d", &a[i]), tot = max(tot, a[i]);
for (int i = 1; i <= tot; ++ i) dp[i] = 0;
for (int i = 1; i <= n; ++ i)
{
for (int j = a[i]; j <= tot; ++ j) dp[j] += dp[j - a[i]];
}
int m = 0;
for (int i = 1; i <= n; ++ i) if(dp[a[i]] == 1) m ++;
printf("%d\n", m);
}
return 0;
}
多重背包问题 III
#include <bits/stdc++.h>
using namespace std;
const int N = 20005;
typedef long long ll;
ll dp[2][N], w;
int n, v, s, V, hh = 0, q[N], tt = 0;
int main()
{
scanf("%d %d", &n, &V);
for (int i = 1; i <= n; ++ i)
{
scanf("%d %lld %d", &v, &w, &s);
for (int k = 0; k < v; ++ k)
{
tt = 1, hh = 0;
for (int j = k; j <= V; j += v)
{
while(tt <= hh && j - q[tt] > s * v) tt ++;
while(tt <= hh && dp[(i & 1) ^ 1][j] >= dp[(i & 1) ^ 1][q[hh]] + (j - q[hh]) / v * w) hh --;
q[++ hh] = j;
dp[i & 1][j] = dp[(i & 1) ^ 1][q[tt]] + (j - q[tt]) / v * w;
}
}
}
printf("%lld", dp[n & 1][V]);
return 0;
}
庆功会
#include <bits/stdc++.h>
using namespace std;
const int M = 6005;
int dp[2][M], n, m, tt, hh, stk[M];
int main()
{
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; ++ i)
{
int v, w, s;
scanf("%d %d %d", &v, &w, &s);
for (int j = 0; j <= v - 1; ++ j)
{
// for (int k = 0; k <= s; ++ k)
// {
// if(j - k * v >= 0) dp[j] = max(dp[j], dp[j - k * v] + k * w);
// }
tt = 1, hh = 0;
for (int k = j; k <= m; k += v)
{
while(tt <= hh && k - stk[tt] > s * v) tt ++;
while(tt <= hh && dp[i & 1][k] >= (k - stk[hh]) / v * w + dp[i & 1][stk[hh]]) hh --;
stk[++ hh] = k;
dp[(i & 1) ^ 1][k] = dp[i & 1][stk[tt]] + (k - stk[tt]) / v * w;
}
}
}
printf("%d", dp[(n & 1) ^ 1][m]);
}
混合背包问题
#include <bits/stdc++.h>
using namespace std;
const int N = 1005;
int dp[2][N], n, V, q[N];
int main()
{
scanf("%d %d", &n, &V);
for (int i = 1; i <= n; ++ i)
{
int v, w, s;
scanf("%d %d %d", &v, &w, &s);
if(s == -1)
{
for (int j = V; j >= v; -- j)
{
dp[i & 1][j] = max(dp[i & 1][j], dp[i & 1 ^ 1][j - v] + w);
}
for (int j = v - 1; j >= 0; -- j) dp[i & 1][j] = dp[i & 1 ^ 1][j];
}
else if(s == 0)
{
for (int j = 0; j <= v - 1; ++ j) dp[i & 1][j] = dp[i & 1 ^ 1][j];
for (int j = v; j <= V; ++ j)
{
dp[i & 1][j] = dp[i & 1 ^ 1][j];
dp[i & 1][j] = max(dp[i & 1][j], dp[i & 1][j - v] + w);
}
}
else
{
for (int j = 0; j < v; ++ j)
{
int tt = 1, hh = 0;
for (int k = j; k <= V; k += v)
{
while(tt <= hh && k - q[tt] > s * v) tt ++;
while(tt <= hh && dp[i & 1 ^ 1][k] >= dp[i & 1 ^ 1][q[hh]] + (k - q[hh]) / v * w) hh --;
q[++ hh] = k;
dp[i & 1][k] = dp[i & 1 ^ 1][q[tt]] + (k - q[tt]) / v * w;
}
}
}
}
printf("%d", dp[n & 1][V]);
return 0;
}
二维费用的背包问题
#include <bits/stdc++.h>
using namespace std;
const int N = 105;
int dp[N][N], n, V, M;
int main()
{
scanf("%d %d %d", &n, &V, &M);
for (int i = 1; i <= n; ++ i)
{
int v, m, w;
scanf("%d %d %d", &v, &m, &w);
for (int j = V; j >= v; -- j)
{
for (int k = M; k >= m; -- k)
{
dp[j][k] = max(dp[j][k], dp[j - v][k - m] + w);
}
}
}
printf("%d", dp[V][M]);
}
潜水员
#include <bits/stdc++.h>
using namespace std;
const int N = 305;
int n, m, k, dp[N][N];
int main()
{
scanf("%d %d %d", &n, &m, &k);
memset(dp, 0x3f, sizeof(dp));
dp[0][0] = 0;
for (int i = 1; i <= k; ++ i)
{
int a, b, c;
scanf("%d %d %d", &a, &b, &c);
for (int x = n; x >= 0; -- x)
{
for (int y = m; y >= 0; -- y)
{
dp[x][y] = min(dp[x][y], dp[max(0, x - a)][max(0, y - b)] + c);
}
}
}
printf("%d", dp[n][m]);
return 0;
}
机器分配
#include <bits/stdc++.h>
using namespace std;
const int N = 15, M = 20;
int n, m, dp[N][M], f[N][M], val[N][M];
void dfs(int x, int y)
{
if(x == 0) return ;
printf("%d %d\n", x, f[x][y]);
dfs(x - 1, y - f[x][y]);
}
int main()
{
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; ++ i)
{
for (int j = 1; j <= m; ++ j)
{
int w;
scanf("%d", &w);
for (int k = j; k <= m; ++ k)
{
if(k - j >= 0 && dp[i][k] < dp[i - 1][k - j] + w)
{
dp[i][k] = dp[i - 1][k - j] + w;
f[i][k] = j;
}
if(dp[i][k] < dp[i - 1][k]) dp[i][k] = dp[i - 1][k], f[i][k] = 0;
}
val[i][j] = w;
}
}
printf("%d\n", dp[n][m]);
dfs(n, m);
}
开心的金明
#include <bits/stdc++.h>
using namespace std;
const int N = 30005;
int n, dp[N], m;
int main()
{
scanf("%d %d", &n, &m);
for (int i = 1; i <= m; ++ i)
{
int v, w;
scanf("%d %d", &v, &w);
for (int j = n; j >= v; -- j) dp[j] = max(dp[j], dp[j - v] + v * w);
}
printf("%d", dp[n]);
return 0;
}
有依赖的背包问题
#include <bits/stdc++.h>
using namespace std;
const int N = 105;
int n, dp[N][N], m, rt, v[N], w[N];
vector<int> g[N];
void dfs(int x)
{
for (int i = v[x]; i <= m; ++ i) dp[x][i] = w[x];
for (int i = 0; i < g[x].size(); ++ i)
{
int y = g[x][i];
dfs(y);
for (int j = m; j >= v[x]; -- j)//这是x的总情况
{
for (int k = 0; k <= j - v[x]; ++ k)
{
dp[x][j] = max(dp[x][j], dp[y][k] + dp[x][j - k]);
}
}
}
return ;
}
int main()
{
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; ++ i)
{
int p;
scanf("%d %d %d", &v[i], &w[i], &p);
if(p == -1) rt = i;
else g[p].push_back(i);
}
dfs(rt);
printf("%d", dp[rt][m]);
return 0;
}
背包问题求方案数
#include <bits/stdc++.h>
using namespace std;
const int N = 1005, mod = 1000000000 + 7;
int n, V, v[N], w[N], dp[N], f[N];
int main()
{
scanf("%d %d", &n, &V);
memset(dp, -0x3f, sizeof(dp));
f[0] = 1, dp[0] = 0;
for (int i = 1; i <= n; ++ i)
{
scanf("%d %d", &v[i], &w[i]);
for (int j = V; j >= v[i]; -- j)
{
if(dp[j] < dp[j - v[i]] + w[i]) dp[j] = dp[j - v[i]] + w[i], f[j] = f[j - v[i]];
else if(dp[j] == dp[j - v[i]] + w[i]) f[j] = (f[j] + f[j - v[i]]) % mod;
}
}
int mx = -0x3f3f3f3f, sum = 0;
for (int j = V; j >= 0; -- j) mx = max(mx, dp[j]);
for (int j = V; j >= 0; -- j)
{
if(dp[j] == mx) sum = (sum + f[j]) % mod;
}
printf("%d", sum);
return 0;
}
背包问题求具体方案
#include <bits/stdc++.h>
using namespace std;
const int N = 1005, mod = 1000000000 + 7;
int n, V, v[N], w[N], dp[N][N], f[N][N];
void dfs(int now, int x)
{
if(!now) return ;
if(f[now][x]) printf("%d ", f[now][x]);
dfs(now - 1, x - v[f[now][x]]);
}
int main()
{
scanf("%d %d", &n, &V);
for (int i = 1; i <= n; ++ i)
{
scanf("%d %d", &v[i], &w[i]);
}
for (int i = 1; i <= n; ++ i)
{
int x = n - i + 1;
for (int j = 0; j <= V; ++ j) dp[i][j] = dp[i - 1][j];
for (int j = v[x]; j <= V; ++ j)
{
if(dp[i][j] <= dp[i - 1][j - v[x]] + w[x])
{
dp[i][j] = dp[i - 1][j - v[x]] + w[x];
f[i][j] = x;
}
}
}
dfs(n, V);
return 0;
}
能量石
#include <bits/stdc++.h>
using namespace std;
const int N = 10005;
int T, n, dp[N], sum = 0;
struct node
{
int s, e, l;
friend bool operator < (node a, node b)
{
return 1.0 * a.s / a.l < 1.0 * b.s / b.l;
}
}p[N];
int main()
{
scanf("%d", &T);
for (int t = 1; t <= T; ++ t)
{
scanf("%d", &n);
sum = 0;
for (int i = 1; i <= n; ++ i)
{
scanf("%d %d %d", &p[i].s, &p[i].e, &p[i].l);
sum += p[i].s;
}
sort(p + 1, p + n + 1);
for (int i = 0; i <= sum; ++ i) dp[i] = 0;
for (int i = 1; i <= n; ++ i)
{
for (int j = sum; j >= p[i].s; -- j)
{
dp[j] = max(dp[j], dp[j - p[i].s] + max(0, p[i].e - p[i].l * (j - p[i].s)));
}
}
int ans = 0;
for (int i = 0; i <= sum; ++ i) ans = max(ans, dp[i]);
printf("Case #%d: %d\n", t, ans);
}
return 0;
}
金明的预算方案
不是正解。、。。
#include <bits/stdc++.h>
using namespace std;
const int N = 40005;
int dp[65][N], m, n, rt, v[N], w[N];
vector<int> g[N];
void dfs(int x)
{
for (int i = v[x]; i <= m; i ++) dp[x][i] = v[x] * w[x];
for (int i = 0; i < g[x].size(); ++ i)
{
int y = g[x][i];
dfs(y);
for (int j = m; j >= v[x]; -- j)
{
for (int k = 0; k <= j - v[x]; ++ k) dp[x][j] = max(dp[x][j], dp[y][k] + dp[x][j - k]);
}
}
return ;
}
int main()
{
scanf("%d %d", &m, &n);
bool pd = true;
for (int i = 1; i <= n; ++ i)
{
int p;
scanf("%d %d %d", &v[i], &w[i], &p);
if(v[i] % 100) pd = false;
if(p == 0) g[0].push_back(i);
else g[p].push_back(i);
}
if(pd == false)
{
for (int i = 1; i <= n; ++ i) v[i] = v[i] / 10;
m = (m - m % 10) / 10;
dfs(0);
printf("%d", dp[0][m] * 10);
}
else
{
for(int i = 1; i <= n; ++ i) v[i] = v[i] / 100;
m = (m - m % 100) / 100;
dfs(0);
printf("%d", dp[0][m] * 100);
}
}
状态机模型
大盗阿福
#include <bits/stdc++.h>
using namespace std;
const int N = 100005;
int n, dp[N][2], T;
int main()
{
scanf("%d", &T);
while(T --)
{
scanf("%d", &n);
for (int i = 0; i <= n; ++ i) dp[i][0] = dp[i][1] = 0;
for (int i = 1; i <= n; ++ i)
{
int x;
scanf("%d", &x);
dp[i][1] = max(dp[i - 1][0] + x, dp[i - 1][1]);
dp[i][0] = max(dp[i - 1][1], dp[i - 1][0]);
}
printf("%d\n", max(dp[n][0], dp[n][1]));
}
return 0;
}
股票买卖 IV
#include <bits/stdc++.h>
using namespace std;
const int N = 100001;
int n, dp[N][102], K, a[N];
int tt = 1, hh = 0, q[N];
int main()
{
scanf("%d %d", &n, &K);
for (int i = 1; i <= n; ++ i) scanf("%d", &a[i]);
for (int k = 1; k <= K; ++ k)
{
tt = 1, hh = 0;
for (int i = 1; i <= n; ++ i)
{
dp[i][k] = max(dp[i][k - 1], dp[i - 1][k]);
if(tt <= hh) dp[i][k] = max(dp[i][k], dp[q[tt]][k - 1] + a[i] - a[q[tt] + 1]);
while(tt <= hh && q[tt] > i - 2) tt ++;
while(tt <= hh && dp[q[hh]][k - 1] - a[q[hh] + 1] < dp[i - 1][k - 1] - a[i - 1 + 1]) hh --;
q[++ hh] = i - 1;
// for (int j = 0; j <= i - 2; ++ j)
// {
// dp[i][k] = max(dp[i][k], dp[j][k - 1] + a[i] - a[j + 1]);
// }
}
}
printf("%d", dp[n][K]);
return 0;
}
股票买卖 V
#include <bits/stdc++.h>
using namespace std;
const int N = 100005;
int n, dp[N][2], a[N];
int q[N], cnt = 0;
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; ++ i) scanf("%d", &a[i]);
for (int i = 1; i <= n; ++ i)
{
dp[i][0] = max(dp[i - 1][0], dp[i - 1][1]);
if(cnt) dp[i][1] = max(dp[i][1], dp[q[1]][0] + a[i] - a[q[1] + 1]);
while(cnt && dp[q[cnt]][0] - a[q[cnt] + 1] < dp[i - 1][0] - a[i - 1 + 1]) cnt --;
q[++ cnt] = i - 1;
// for (int j = 0; j <= i - 2; ++ j)
// {
// dp[i][1] = max(dp[i][1], dp[j][0] + a[i] - a[j + 1]);
// }
}
printf("%d", max(dp[n][0], dp[n][1]));
return 0;
}
/*
如果我今天要买入股票,那么我的昨天一定不能卖股票
1代表这一条卖出股票,0代表一天没有卖出股票
*/
设计密码
kmp中的\(next\)数组:\(next[i]\)表示该字符串中\([1, next[i]]\)和\([i - next[i] + 1, i]\)中方的字符串是相同的。
所以匹配子串发现i + 1位置不符合的时候,即前面\([1,i]\)是符合的,只需要用\(next[i] + 1\)的位置和\(i + 1\)再试一遍就可以了。
dp的时候暴力尝试路径,用kmp批判,判断是不是子串就可以了
\(dp[i][j]\)表示在第\(i\)个空位时,前面已经有\(j\)个字母和T相同的方案数
#include <bits/stdc++.h>
using namespace std;
const int N = 55;
int n, dp[N][N], m, nxt[N];
char s[N];
const int mod = 1000000007;
int main()
{
scanf("%d", &n);
scanf("%s", s + 1);
m = strlen(s + 1);
dp[0][0] = 1;
for (int i = 0, j = 2; j <= n; ++ j)
{
while(i && s[i + 1] != s[j]) i = nxt[i];
if(s[i + 1] == s[j]) i ++;
nxt[j] = i;
}
for (int i = 1; i <= n; ++ i)
{
for (int j = 0; j <= m - 1; ++ j)
{
for (int c = 'a'; c <= 'z'; ++ c)
{
int u = j;
while(u && s[u + 1] != c) u = nxt[u];
if(s[u + 1] == c) u ++;
if(u < m) dp[i][u] = (dp[i - 1][j] + dp[i][u]) % mod;
}
}
}
int ans = 0;
for (int i = 0; i <= m - 1; ++ i) ans = (ans + dp[n][i]) % mod;
printf("%d", ans);
return 0;
}
修复DNA
#include <bits/stdc++.h>
using namespace std;
int n, T = 1, idx = 0;
const int N = 1005;
char str[N];
bool dar[N];
int ne[N], f[N][N], q[N], tr[N][4];
int gett(char c)
{
if(c == 'A') return 0;
if(c == 'T') return 1;
if(c == 'G') return 2;
if(c == 'C') return 3;
}
void insert()
{
int len = strlen(str + 1);
int p = 0;
for (int i = 1; i <= len; ++ i)
{
int c = gett(str[i]);
if(!tr[p][c]) tr[p][c] = ++idx, p = idx;
else p = tr[p][c];
}
dar[p] = true;
}
void build_AC()
{
int tt = 1, hh = 0;
for (int i = 0; i < 4; ++ i) if(tr[0][i]) q[++ hh] = tr[0][i];
while(tt <= hh)
{
int p = q[tt ++];
for (int i = 0; i < 4; ++ i)
{
int x = tr[p][i];
if(!x) tr[p][i] = tr[ne[p]][i];
else ne[x] = tr[ne[p]][i], dar[x] |= dar[ne[x]], q[++ hh] = x;
}
}
return ;
}
int main()
{
while(scanf("%d", &n) != EOF)
{
if(!n) break;
memset(dar, 0, sizeof dar);
memset(f, 0x3f, sizeof f);
memset(tr, 0, sizeof tr);
memset(ne, 0, sizeof(ne));
idx = 0;
for (int i =1 ; i <= n; ++ i)
{
scanf("%s", str + 1);
insert();
}
build_AC();
scanf("%s", str + 1);
int m = strlen(str + 1);
f[0][0] = 0;
for (int i = 0; i <= m - 1; ++ i)
{
for (int j = 0; j <= idx; ++ j)
{
for (int k = 0; k < 4; ++ k)
{
int p = tr[j][k];
if(!dar[p]) f[i + 1][p] = min(f[i + 1][p], f[i][j] + (k != gett(str[i + 1])));
}
}
}
int ans = 0x3f3f3f3f;
for (int i = 0; i <= idx; ++ i) if(!dar[i]) ans = min(ans, f[m][i]);
if(ans == 0x3f3f3f3f) ans = -1;
printf("Case %d: %d\n", T ++, ans);
}
return 0;
}
状态压缩DP
小国王
#include <bits/stdc++.h>
using namespace std;
const int N = 1030;
int n, a[1025][25], cnt = 0, K, b[25], num[1025];
typedef long long ll;
ll dp[2][105][1025], ans = 0;
void dfs(int x)
{
if(x == n + 1)
{
int len = 0;
for (int i = 1; i <= n; ++ i) if(b[i]) len ++;
if(len <= K)
{
cnt ++, num[cnt] = len;
for (int i = 1; i <= n; ++ i) a[cnt][i] = b[i];
dp[1][num[cnt]][cnt] = 1ll;
}
return ;
}
if(!(b[x - 1])) b[x] = 1, dfs(x + 1);
b[x] = 0, dfs(x + 1);
return ;
}
bool check(int x, int y)
{
for (int i = 1; i <= n; ++ i)
{
if(a[x][i] && a[y][i]) return false;
if(a[x][i] && a[y][i + 1]) return false;
if(a[x][i + 1] && a[y][i]) return false;
if(a[x][i] && a[y][i - 1]) return false;
if(a[x][i - 1] && a[y][i]) return false;
}
return true;
}
int main()
{
scanf("%d %d", &n, &K);
dfs(1);
for (int i = 2; i <= n; ++ i)
{
for (int k = 0; k <= K; ++ k)
{
for (int x = 1; x <= cnt; ++ x)
{
dp[i & 1][k][x] = 0;
}
}
for (int k = 0; k <= K; ++ k)
{
for (int x = 1; x <= cnt; ++ x)
{
for (int y = 1; y <= cnt; ++ y)
{
if(check(x, y) && num[x] <= k && k - num[x] >= num[y]) dp[i & 1][k][x] += dp[i & 1 ^ 1][k - num[x]][y];
}
}
}
}
for (int i = 1; i <= cnt; ++ i) ans += dp[n & 1][K][i];
printf("%lld", ans);
return 0;
}
区间DP
环形石子合并
#include <bits/stdc++.h>
using namespace std;
const int N = 405;
int n, dpm[N][N], dpx[N][N], a[N], sum[N];
int ansm = 0x3f3f3f3f, ansx = 0;
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n; ++ i) scanf("%d", &a[i]), a[i + n] = a[i];
memset(dpm, 0x3f, sizeof dpm);
for (int i = 1; i <= n + n; ++ i) dpm[i][i] = dpx[i][i] = 0;
for (int i = 1; i <= n + n; ++ i) sum[i] = sum[i - 1] + a[i];
for (int len = 2; len <= n; ++ len)
{
for (int i = 1; i + len - 1 <= n + n; ++ i)
{
int j = i + len - 1;
for (int k = i; k <= j - 1; ++ k)
{
dpx[i][j] = max(dpx[i][j], dpx[i][k] + dpx[k + 1][j] + sum[j] - sum[i - 1]);
dpm[i][j] = min(dpm[i][j], dpm[i][k] + dpm[k + 1][j] + sum[j] - sum[i - 1]);
}
}
}
for (int i = 1; i <= n; ++ i)
{
ansm = min(ansm, dpm[i][i + n - 1]);
ansx = max(ansx, dpx[i][i + n - 1]);
}
printf("%d\n%d", ansm, ansx);
}
树形DP
树的最长路径
#include <bits/stdc++.h>
using namespace std;
const int N = 10004;
int n, dp[N][2], ans = 0;
struct edge
{
int v, w;
};
vector<edge> g[N];
void dfs(int x, int fa)
{
for (int i = 0; i < g[x].size(); ++ i)
{
int y = g[x][i].v, w = g[x][i].w;
if(y == fa) continue;
dfs(y, x);
if(dp[x][0] <= dp[y][0] + w)
{
dp[x][1] = dp[x][0], dp[x][0] = dp[y][0] + w;
}
else if(dp[x][1] < dp[y][0] + w) dp[x][1] = dp[y][0] + w;
}
return ;
}
int main()
{
scanf("%d", &n);
for (int i = 1; i <= n - 1; ++ i)
{
int u, v, w;
scanf("%d %d %d", &u, &v, &w);
g[u].push_back((edge){v, w});
g[v].push_back((edge){u, w});
}
dfs(1, 0);
for (int i = 1; i <= n; ++i) ans = max(ans, dp[i][0] + dp[i][1]);
printf("%d", ans);
return 0;
}
/*
只需要计算一个节点的最长路径和次长路径
*/
数位DP
度的数量
#include <bits/stdc++.h>
using namespace std;
const int N = 35;
int l, r, k, b, f[N][N];
void init()
{
f[0][0] = 1;
for (int i = 1; i <= 31; ++ i)
{
for (int j = 0; j <= i; ++ j)
{
if(!j) f[i][j] = 1;
else f[i][j] = f[i - 1][j] + f[i - 1][j - 1];
}
}
}
int dp(int n)
{
int res = 0, last = 0;
vector<int> nums;
while(n)
{
nums.push_back(n % b);
n /= b;
}
for (int i = nums.size() - 1; i >= 0; -- i)
{
int x = nums[i];
if(x)
{
res += f[i][k - last];
if(x > 1)
{
if(k - last - 1 >= 0) res += f[i][k - last - 1];
break;
}
else
{
last ++;
if(last > k) break;
}
}
if(!i && k == last) res += 1;
}
return res;
}
int main()
{
scanf("%d %d %d %d", &l, &r, &k, &b);
init();
printf("%d", dp(r) - dp(l - 1));
return 0;
}
数字游戏
#include <bits/stdc++.h>
using namespace std;
const int N = 35;
int l, r, f[N][11];
void init()
{
for (int x = 0; x <= 9; ++ x) f[1][x] = 1;
for (int i = 2; i <= 31; ++ i)
{
for (int x = 9; x >= 0; -- x)
{
for (int y = x; y <= 9; ++ y)
{
f[i][x] += f[i - 1][y];
}
}
}
return ;
}
int dp(int n)
{
if(n == 0) return 1;
int res = 0, last = 0;
vector<int> nums;
while(n)
{
nums.push_back(n % 10);
n /= 10;
}
for (int i = nums.size() - 1; i >= 0; -- i)
{
int x = nums[i];
if(x >= last) for (int j = last; j <= x - 1; ++ j) res += f[i + 1][j];
else break;
if(!i && x >= last) res ++;
last = x;
}
return res;
}
int main()
{
init();
while(scanf("%d %d", &l, &r) != EOF)
{
printf("%d\n", dp(r) - dp(l - 1));
}
return 0;
}
Windy数
#include <bits/stdc++.h>
using namespace std;
int f[35][11], l, r;
void init()
{
for (int x = 0; x <= 9; ++ x) f[1][x] = 1;
for (int i = 2; i <= 31; ++ i)
{
for (int x = 0; x <= 9; ++ x)
{
for (int y = 0; y <= x - 2; ++ y) f[i][x] += f[i - 1][y];
for (int y = x + 2; y <= 9; ++ y) f[i][x] += f[i - 1][y];
}
}
return ;
}
int dp(int n)
{
if(n == 0) return 1;
int res = 0, last = -1;
vector<int> nums;
while(n)
{
nums.push_back(n % 10);
n /= 10;
}
for (int i = nums.size() - 1; i >= 0; -- i)
{
int x = nums[i];
for (int y = 0; y <= x - 1; ++ y)
{
if(abs(y - last) >= 2) res += f[i + 1][y];
}
if(abs(x - last) < 2) break;
if(!i) res ++;
last = x;
}
for (int i = 1; i <= nums.size() - 1; ++ i)
{
for (int j = 1; j <= 9; ++ j) res += f[i][j];
}
res ++;
return res;
}
int main()
{
init();
scanf("%d %d", &l, &r);
printf("%d", dp(r) - dp(l - 1));
return 0;
}
数字游戏 II
#include <bits/stdc++.h>
using namespace std;
int f[11][11][105], p, l, r;
void init()
{
memset(f, 0, sizeof(f));
f[0][0][0] = 1;
for (int i = 1; i <= 10; ++ i)
{
for (int x = 0; x <= 9; ++ x)
{
for (int y = 0; y <= 9; ++ y)
{
for (int k = 0; k <= p - 1; ++ k) f[i][x][(k + x) % p] += f[i - 1][y][k];
}
}
}
return ;
}
int dp(int n)
{
int res = 0, last = 0;
vector<int> nums;
if(n == 0) return 1;
while(n)
{
nums.push_back(n % 10);
n /= 10;
}
for (int i = nums.size() - 1; i >= 0; -- i)
{
int x = nums[i];
for (int j = 0; j <= x - 1; ++ j)
{
for (int k = 0; k <= 9; ++ k) res += f[i][k][(((p - j - last) % p) + p) % p];
}
last += x;
if(!i && last % p == 0) res ++;
}
return res;
}
int main()
{
while(scanf("%d %d %d", &l, &r, &p) != EOF)
{
init();
printf("%d\n", dp(r) - dp(l - 1));
}
return 0;
}

浙公网安备 33010602011771号