DP Contest
A - Frog 1
发现 \(f[i]\) 只能从 \(f[i - 1], f[i - 2]\) 跳过来。
所以转移方程为 \(f[i] = min(f[i - 1] + abs(h[i] - h[i - 1], f[i - 2] + abs(h[i] - h[i - 2]) )\)。
注意初始化 \(f[1] = 0, f[2] = abs(h[2] - h[1]])\)。
int f[N], h[N], k;
signed main()
{
int n = read();
for(int i = 1; i <= n; i++) h[i] = read();
f[1] = 0, f[2] = abs(h[2] - h[1]);
for(int i = 3; i <= n; i++) {
f[i] = min(f[i - 1] + abs(h[i] - h[i - 1]), f[i - 2] + abs(h[i] - h[i - 2]));
}
cout << f[n];
return 0;
}
B - Frog 2
这次这次青蛙可以一次跳 \([1, k]\) 里面的任意一步。
转移方程为 \(f[i] = min(f[i], f[i - j] + abs(h[i] - h[i - j]))1 \le j \le k \& i - j > 0\)。
注意一开始赋极大值。
signed main()
{
n = read(), k = read();
for(int i = 1; i <= n; i++) a[i] = read();
memset(f, 63, sizeof f);
f[1] = 0;
for(int i = 2; i <= n; i++) {
for(int j = 1; j <= k; j++) {
if(i - j >= 1) f[i] = min(f[i], f[i - j] + abs(a[i] - a[i - j]));
}
}
cout << f[n];
return 0;
}
C - Vacation
不能连续两天选重复的。
我们设 \(dp[i][j]\) 表示第 \(i\) 天选了第 \(a[i][j]\)。
我们如何知道两天不能选重复的?
我们这两天的状态都枚举即可。
转移方程为 $ if(j \ne k) dp[i][j] = max(dp[i][j], dp[i - 1][k] + a[i][j]) $
int a[N][5];
int dp[N][5];
signed main()
{
int n = read();
for(int i = 1; i <= n; i++)
for(int j = 1; j <= 3; j++)
a[i][j] = read();
for(int i = 1; i <= 3; i++) dp[1][i] = a[1][i];
for(int i = 2; i <= n; i++) {
for(int j = 1; j <= 3; j++) {
for(int k = 1; k <= 3; k++) {
if(j != k) dp[i][j] = max(dp[i][j], dp[i - 1][k] + a[i][j]);
}
}
}
cout << max(dp[n][1], max(dp[n][2], dp[n][3]));
return 0;
}
D - Knapsack 1
\(01\) 背包的板子题。
int n, V;
ll w[N], val[N], dp[N];
signed main()
{
n = read(), V = read();
for(int i = 1; i <= n; i++) w[i] = read(), val[i] = read();
for(int i = 1; i <= n; i++) {
for(int j = V; j >= w[i]; j--) {
dp[j] = max(dp[j], dp[j - w[i]] + val[i]);
}
}
cout << dp[V];
return 0;
}