poj3616 Milking Time(动态规划)

题目链接:http://poj.org/problem?id=3616

题目大意:奶牛Bessie准备在未来的N(1<=N<=1,000,000)小时内产奶,fj会来取M(1<=M<=1,000)次,

每次取奶时间为 [s, e),产量为w。奶牛每产一次奶需要休息R小时(1<=R<=N)。问最大取奶量。

动态规划:本题类型为区间权重dp。策略是按照取奶结束时间e由小到大排序,然后维护一个数组pre。

pre[i]保存的是区间 i 的前面的最接近 i 且不冲突的区间 j 的下标。

动态规划方程为:dp[i] = max(dp[i-1], dp[p[i]]+w[i])

dp[i]为前i个区间可获得的最大产奶量。w[i]为第i个区间的产奶量。

 

这么说pre可能有点绕,举个栗子助于理解下:

针对题目样例数据排序后为(下标从1开始):

(1 2 8),(3 6 24),(7 10 31),(10 12 19)

那么pre = { 0,0,1,2 }。

为什么是0 0 1 2呢,因为和区间(1 2 8)不冲突的最后一个区间是区间0(0 0 0),同理区间(3 6 24)也是。

对于(7 10 31)而言(3 6 24)是冲突的,因为6时结束产奶休息两小时,8时才可以继续产奶,与本区间时间冲突了。

再往前看一个(1 2 8)和本区间是不冲突的,因为2时产完奶休息两小时,4时即可开始产奶,与本区间没有冲突。

所以pre[3] = 1;  同样的道理处理区间(10 12 19)得到pre[4] = 2;

 

那么问题来了,为什么要维护这样一个数组pre呢?

dp[i]维护的是前i个区间的最大产奶量。那么dp[i]要么是不收集本区间(i)的产奶量,直接从区间[i-1]过来。

要么是收集本区间的产奶量 w[i],及前面最大的不冲突的产奶量和(即dp[p[i]])。

找到最近的一个不冲突的区间 p[i] 即可算去前面最大的不冲突的产奶量和。

然后取这两者的最大值,即是前 i 个区间的最大产奶量和。

 

然后问题是动态规划的边缘值dp[0]。这里处理的方式是区间从1开始,那么前0个区间的最大产奶量就是0了。

在最前面添加了一个区间0(0 0 0) 也保证了所有区间都可以找到一个不越界的 pre区间。

 

Sample Input

12 4 2
1 2 8
10 12 19
3 6 24
7 10 31

Sample Output

43

 

下面是已AC的代码:

#include <iostream>
#include <cstdio>
#include <algorithm>

using namespace std;

struct ST{
        int s, e, f;
} st[1010];

long long dp[1010]; // dp[i] 保存前i个区间的最大sum值
int pre[1010]; // pre[i] 保存了区间i最近的那个不与区间i冲突的区间

bool cmp( const ST& s1, const ST& s2 ) {
        return s1.e < s2.e;
}

void cal_pre( const int M, const int R ) {
        for ( int i = 1 ; i <= M ; ++ i ) {
                pre[i] = 0; // 预保存一个0值
                for ( int j = i-1 ; j >= 0 ; -- j ) {
                        if ( st[j].e+R <= st[i].s ) {
                                pre[i] = j;
                                break;
                        }
                }
        }
}

int main()
{
        int N, M, R;
        scanf( "%d%d%d", &N, &M, &R );
        for ( int i = 1 ; i <= M ; ++ i ) {
                scanf( "%d%d%d", &st[i].s, &st[i].e, &st[i].f );
        }
        sort( st+1, st+M+1, cmp );
        cal_pre(M, R);

        for ( int i = 1 ; i <= M ; ++ i ) {
                dp[i] = max(dp[i-1], dp[pre[i]]+st[i].f);
        }

        printf("%d\n", dp[M]);

        return 0;
}

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值