[USACO19DEC]Greedy Pie Eaters P 題解
阿新 • • 發佈:2020-10-31
題目連結: https://www.luogu.com.cn/problem/P5851
題意:
\(N\) 個派, \(M\) 只奶牛。第 \(i\) 只奶牛體重為 \(W_i\) 吃 \([L_i,R_i]\) 中的,每次吃都會吧這個區間中所有剩下的吃完。求選擇一些奶牛且恰當安排順序使得吃到派的奶牛的體重之和最大。 \((1\le L_i,R_i\le N\le300,1\le M\le\frac{N(N-1)}{2},1\le W_i\le10^6)\)
題解:
每次考慮通過一個被吃光的連續區間來轉移(其實沒被吃光也無所謂,反正不選就是了)。
因此設 \(F(i,j)\) 為已經選完 \([i,j]\)
區間 DP 的常見套路:列舉中間端點:
-
\(F(i,j)=\max\left\{F(i,k)+F(k+1,j)\right\}(i\le k<j)\)
-
\(F(i,j)=\max\left\{F(i,k-1)+F(k+1,j)+A(i,j,k)\right\}(1\le j\le k)\)
其中 \(A(i,j,k)\) 表示被包含在 \([i,j]\) 中,幷包含 \(k\) 這個點的最大奶牛體重。
所以怎麼求這個東西呢?又可以採用區間 DP 的套路,對於 \([i,j]\) ,從 \([i+1,j]\) 和 \([i,j-1]\) 轉移。
程式碼非常清晰,可以直接看。時間複雜度: \(O(N^3)\)
程式碼:
#include <bits/stdc++.h> using namespace std; const int N=305; int n,m,f[N][N],a[N][N][N]; signed main(){ scanf("%d%d",&n,&m); while(m--){ int w,l,r;scanf("%d%d%d",&w,&l,&r); for(int i=l;i<=r;i++) a[l][r][i]=w; } for(int i=n;i;i--) for(int j=i;j<=n;j++){ if(i!=1) for(int k=i;k<=j;k++) a[i-1][j][k]=max(a[i-1][j][k],a[i][j][k]); if(j!=n) for(int k=i;k<=j;k++) a[i][j+1][k]=max(a[i][j+1][k],a[i][j][k]); } for(int i=n;i;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],f[i][k-1]+f[k+1][j]+a[i][j][k]); } printf("%d\n",f[1][n]); return 0; }