洛谷P5851 [USACO19DEC]Greedy Pie Eaters P
一道不错的区间DP题目,刚开始做的时候没有想到需要两次DP,所以做题还是要更加深入思考。
P5851 [USACO19DEC]Greedy Pie Eaters P
\(Solution\):\(f[i][j]\)来表示将区间\([i,j]\)全部吃掉的最大\(w\).则可写出方程:
\[f[i][j]=max(f[i][k-1]+f[k+1][j]+p[k][i][j])
\]
\(p[k][i][j]\)表示用吃饼范围在\([i,j]\)区间的牛的最大w,此时\(k\)还未被吃
解释一下方程,合并时要满足\(k\)号饼还没有被吃掉,所以是\(f[i][k-1]+f[k+1][j]\)
\(p[k][i][j]\)可以提前预处理出来,一位一位向外拓展即可.
Tips区间DP一定要注意循环顺序!
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 310;
int n, m, p[N][N][N], f[N][N];
struct Cow {
int w, l, r;
} cow[N*(N-1)/2];
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; i++) {
int w, l, r; scanf("%d%d%d", &w, &l, &r);
for (int j = l; j <= r; j++)
p[j][l][r] = w;
}
for (int k = 1; k <= n; k++)
for (int i = k; i >= 1; i--)
for (int j = k; j <= n; j++) {
if (i != 1) {
p[k][i-1][j] = max(p[k][i][j], p[k][i-1][j]);
}
if (j != n) {
p[k][i][j+1] = max(p[k][i][j], p[k][i][j+1]);
}
}
for (int i = n; i >= 1; i--)
for (int j = i; j <= n; j++) {
for (int k = i; k < j; k++)
f[i][j] = max(f[i][j], f[i][k] + f[k+1][j]);
for (int k = i; k <= j; k++)
f[i][j] = max(f[i][j], (k != i ? f[i][k-1] : 0) + (k != j ? f[k+1][j] : 0) + p[k][i][j]);
}
printf("%d\n", f[1][n]);
return 0;
}

浙公网安备 33010602011771号