POJ 2228 Naptime 环状DP


一个环,分成 N 个区间,每个区间有个权值,你可以选择 B 个不同的区间,这些区间可以连续也可以不连续。

那么如何使得选中的区间中的权值之和最大。有个限制条件,被选中的任何连续区间,第一个区间的权值是不算的。

比如你选中编号为 k, k + 1, k + 2 的这 3 个区间时,第编号 k 的区间的权值是不算进去的,

只能算后两个区间 k + 1 和 k + 2 区间的权值之和(但是你损耗了 3 个区间,而不是两个)。

只选择单个区间的时候也是一样,单个区间的权值算作 0。


#include <iostream>
#include <cstring>
using namespace std;

const int inf = 99999999;
const int sleep = 1;
const int active = 0;

long long DP[2][2][3900];
int utilities[3900];
int periods;
int can_be_used;


void dp_solve(){
    for( int period = 2; period <= periods; ++period ){
        for( int used = 0; used <= can_be_used; ++used ){
            DP[period % 2][active][used] = max( DP[( period - 1 ) % 2][sleep][used],
                                                DP[( period - 1 ) % 2][active][used] );
            if( used > 0 )
                DP[period % 2][sleep][used] = max( DP[( period - 1 ) % 2][sleep][used - 1] + utilities[period],
                                                   DP[( period - 1 ) % 2][active][used - 1] );
            else
                DP[period % 2][sleep][used] = -inf;
        }
    }
}


int main(){

    while( cin >> periods >> can_be_used ){

        for( int period = 1; period <= periods; ++period )
            cin >> utilities[period];

        for( int used = 0; used <= can_be_used; ++used ){
            DP[1][sleep][used]  = -inf;
            DP[1][active][used] = -inf;
        }

        DP[1][active][0] = 0;
        DP[1][sleep][1]  = 0;
        dp_solve();

        int ans1 = max( DP[periods % 2][sleep][can_be_used],
                        DP[periods % 2][active][can_be_used] );

        for( int used = 0; used <= can_be_used; ++used ){
            DP[1][sleep][used] = -inf;
            DP[1][active][used] = -inf;
        }

        DP[1][sleep][1] = 0;
        dp_solve();

        int ans2 = max( DP[periods % 2][sleep][can_be_used] + utilities[1],
                        DP[periods % 2][active][can_be_used] );
        int ans = max( ans1, ans2 );

        cout << ans << endl;

    }

    return 0;

}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值