洛谷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;
}
posted @ 2020-11-30 21:42  lew2018  阅读(125)  评论(1)    收藏  举报
Live2D