P1877 [HAOI2012]音量调节

P1877 [HAOI2012]音量调节

到达型01背包问题,开个bool的dp数组.

此外还有滚动数组的用法.

 

 

 bool dp[i][j] 表示前i首歌能否到达j音量,则dp[0][beginLevel] = true.

如果上一首歌音量能够达到j + s[i] 或 j - s[i], 那么当前歌曲就可以达到j,注意处理越界情况.

尝试压维,变成dp[j],有如下代码:

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

int n, be, ma, s[60];
bool dp[1010];

int main(){
    cin >> n >> be >> ma;
    for(int i = 0; i < n; i++) cin >> s[i];

    dp[be] = true;
    for(int i = 0; i < n; i++)
        for(int j = ma; j >= 0; j--)
            if(j - s[i] >= 0)
                if(j + s[i] <= ma) dp[j] = dp[j - s[i]] || dp[j + s[i]];
                else dp[j] = dp[j - s[i]];
            else    // j - s[i] < 0
                if(j + s[i] <= ma) dp[j] = dp[j + s[i]];
                else dp[j] = false;

    

    return 0;
}

调试几下发现错得一塌糊涂.这里面的问题在于涉及到dp[j + s[i]],由于数组的覆盖问题,j + s[i]总是为已经更新的当前歌曲(从i更新到i + 1)的状态,这是个错误.

为了避免这种干扰,来一招滚动数组轻松解决问题:

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

int n, be, ma, s[60];
bool dp[2][1010];

int main() {
    cin >> n >> be >> ma;
    for (int i = 0; i < n; i++) cin >> s[i];

    dp[0][be] = true;
    for (int i = 0; i < n; i++)
        for (int j = ma; j >= 0; j--)
            if (j - s[i] >= 0)
                if (j + s[i] <= ma)
                    dp[(i + 1) & 1][j] = dp[i & 1][j - s[i]] || dp[i & 1][j + s[i]];
                else
                    dp[(i + 1) & 1][j] = dp[i & 1][j - s[i]];
            else  // j - s[i] < 0
                if (j + s[i] <= ma)
                dp[(i + 1) & 1][j] = dp[i & 1][j + s[i]];
            else
                dp[(i + 1) & 1][j] = false;

    for(int i = ma; i >= 0; i--)
        if(dp[n & 1][i]){
            cout << i << endl;
            return 0;
        }
    puts("-1");

    return 0;
}

这里 按位与 "&" 用以判断奇偶数.

所以,虽然书上说开bool的dp经常会很浪费,但只要能够解决问题的时候不要思考受限,开它.

posted @ 2020-12-08 16:00  goverclock  阅读(145)  评论(0编辑  收藏  举报