1. 程式人生 > 實用技巧 >洛谷P5851 [USACO19DEC]Greedy Pie Eaters P

洛谷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;
}