题意:在一维上有n块草坪,给出每块草坪的位置(可以看做是x轴上的整数点),Bessie初始位于L位置,他可以向左右两个方向去吃草坪,假设吃草坪的时间不计,路上的时间是每走一个单位,时间+1,每块草坪都有一个staleness值,这个值恰好等于Bessie到达的时间,现在要求的是Bessie将所有草坪吃完,所有草坪的staleness值之和最小。
思路:这是一道区间DP的问题,我们用dp[i][j][0]表示从i-j区间都吃完,最后停留在i位置,所有草坪的最小的staleness值;dp[i][j][1]表示i-j区间都吃完,最后停留在j位置,所有草坪的最小的staleness值。(显然i~j都吃完之后不可能停在中间。因为如果i、j都吃完了,那么从i到j或者从j到i必然经过了中间的所有点)。那么这两个状态的转移方程就是:
dp[i][j][0] = min(dp[i+1][j][0]+(s[i+1]-s[i])*k , dp[i+1][j][1]+(s[j]-s[i])*k);//k是剩下多少草没吃,它们的staleness值要增加,而s[i+1]-s[i]之类的是最后一段行走的距离,也即增加量。
dp[i][j][1] = min(dp[i][j-1][0]+(s[j]-s[i])*k , dp[i][j-1][1]+(s[j]-s[j-1])*k);
其中k = n-(j-i);
注意把起始点也添加进了草点,这样便于计算。
注意计算顺序,这样的计算顺序才能保证方程中的式子已经先被计算出来了。
#include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <algorithm> #include <queue> using namespace std; #define INF 0x3fffffff #define clr(s,t) memset(s,t,sizeof(s)) #define N 1005 int dp[N][N][2],s[N]; int n,b; int main(){ int i,j,k; scanf("%d %d",&n,&b); for(i = 1;i<=n;i++) scanf("%d",&s[i]); s[++n] = b; sort(s+1,s+n+1); b = lower_bound(s+1, s+n+1, b)-s; for(i = 1;i<=n;i++) for(j = 1;j<=n;j++) dp[i][j][0] = dp[i][j][1] = INF; dp[b][b][0] = dp[b][b][1] = 0; for(i = b;i>=1;i--){ for(j = b;j<=n;j++){ if(i==j) continue; k = n-(j-i); dp[i][j][0] = min(dp[i+1][j][0]+(s[i+1]-s[i])*k , dp[i+1][j][1]+(s[j]-s[i])*k); dp[i][j][1] = min(dp[i][j-1][0]+(s[j]-s[i])*k , dp[i][j-1][1]+(s[j]-s[j-1])*k); } } printf("%d\n",min(dp[1][n][0],dp[1][n][1])); return 0; }