POJ 3042 动态规划 区间DP

POJ 3042 区间DP,这道题有点技巧。如果把状态转移方程定义为dp[i][j]:=吃光从i-j的草,i-j的草的新鲜度之和,是求不出来状态转移表达式的。原因很简单,因为忽视了吃光所有的草的时候牛站在区间哪一侧的重要信息。

一个比较好的定义是这样的:dp[i][j][1]:=吃光i-j的草的时候,牛站在j位置,此时此刻全部的草的新鲜度之和,0则代表站在i位置。

这样可以很容易的求出状态转移方程:

dp[i][j][1] = min(dp[i][j - 1][1] + (arr[j] - arr[j - 1]) * (N - (j - i)),

                          dp[i][j - 1][0] + (arr[j] - arr[i]) * (N - (j - i)))

以上方程讨论了吃到j的时候,是从i位置过来的好还是从j-1位置过来的,(arr[j] - arr[j - 1]) * (N - (j - i))的意义是:从j-1的位置走到j还有N-(j-i)个草没有被吃,他们的新鲜度全部加上arr[j] - arr[j - 1]。

此题可见,状态方程的定义,是十分重要的。

在状态转移方程定义时将区间端点的左右也建立成状态,最近遇到了3次,对于区间左右的01表示是一个值得学习的技巧。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int N, L;
int arr[1001];
int dp[1001][1001][2];
int main(){
    scanf("%d %d", &N, &L);
    for(int i = 1; i <= N; i ++){
        scanf("%d", arr + i);
    }
    sort(arr + 1, arr + 1 + N);
    for(int i  = 1; i <= N; i ++){
        dp[i][i][0] = dp[i][i][1] = N * abs(L - arr[i]);
    }
    for(int l = 2; l <= N; l ++){
        for(int i = 1, j = i + l - 1; j <= N; j ++, i ++){
            dp[i][j][1] = min(dp[i][j - 1][1] + (N - j + i) * (arr[j] - arr[j - 1]), dp[i][j - 1][0] + (N - j + i) * (arr[j] - arr[i]));
            dp[i][j][0] = min(dp[i + 1][j][1] + (N - j + i) * (arr[j] - arr[i]), dp[i + 1][j][0] + (N - j + i) * (arr[i + 1] - arr[i]));
        }
    }
    printf("%d\n", min(dp[1][N][1], dp[1][N][0]));
}

 

转载于:https://my.oschina.net/fuchuanpu/blog/3051937

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值