poj 3042 区间dp(草的过期程度最小)

题意:在一维上有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;
}


你可能感兴趣的:(poj 3042 区间dp(草的过期程度最小))