洛谷P5851 [USACO19DEC]Greedy Pie Eaters P
阿新 • • 發佈:2020-11-30
一道不錯的區間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; }