动态规划-音量调节

[HAOI2012]音量调节

https://ac.nowcoder.com/acm/problem/19990

对于%60的数据,递归是个简单又容易理解的方法。初学者可用此法:
思路:每次递归有两种情况:加或减。即: solve(curLevel + a[t], t + 1);
solve(curLevel - a[t], t + 1);

#include <cstdio>
#include <iostream>

using namespace std;

const int maxn = 105;
int n, beginLevel, maxLevel, ans = -maxn;
int a[maxn];
// 快速读入(可以替换成scanf或printf)
void read(int &x) {
    int p = 1;
    char c = getchar();
    while (c < '0' || c > '9') {
        if (c == '-') {
            p = -1;
        }
        c = getchar();
    }
    while (c >= '0' && c <= '9') {
        x = (x << 1) + (x << 3) + (c ^ 48);
        c = getchar();
    }
}
//核心代码
bool solve(int curLevel, int t) {//curLevel表示当前音量,t表示第t首曲子
    if (curLevel > maxLevel || curLevel < 0) {
        return false;
    }
        //已经是最后一首曲子,更新最大值ans
    if (t == n + 1) {
        ans = max(ans, curLevel);
        return true;
    }
    bool plus = solve(curLevel + a[t], t + 1);
    bool minus = solve(curLevel - a[t], t + 1);
        //若尝试两种情况都失败了
    if (!plus && !minus) {
        return false;
    }
    return true;
}

int main() {
    read(n), read(beginLevel), read(maxLevel);
    for (int i = 1; i <= n; i++) {
        read(a[i]);
    }
    if (solve(beginLevel, 1)) {
        printf("%d\n", ans);
    } else {
        printf("-1\n");
    }

    return 0;
}
/*
input:
3 5 10               
5 3 7
output:
10
*/

但是如何做到满分呢?这里我先说明超时原因:递归的效率比递推效率低很多
这题数据量小,可以不用大佬们所说的“滚动数组”。
1.令bool dp[i][j]为第i首曲子是否能达到音量j
2.转移方程:dp[i][j-a[i]]=1,dp[i][j+a[i]]=1.当然要有判断,是否超出音量范围。
附上满分代码如下:

#include <cstdio>
#include <iostream>

using namespace std;

const int maxn = 105;
int n, beginLevel, maxLevel, ans = -maxn;
int a[maxn];
bool f[maxn][maxn * 100];
// f[i][j]表示第i首曲子所能达到的音量 

void read(int &x) {
    int p = 1;
    char c = getchar();
    while (c < '0' || c > '9') {
        if (c == '-') {
            p = -1;
        }
        c = getchar();
    }
    while (c >= '0' && c <= '9') {
        x = (x << 1) + (x << 3) + (c ^ 48);
        c = getchar();
    }
}

int main() {
    read(n), read(beginLevel), read(maxLevel);
    for (int i = 1; i <= n; i++) {
        read(a[i]);
    }
    f[0][beginLevel] = 1;
    for (int i = 1; i <= n; i++) {
        // 外层循环枚举曲子
        for (int j = maxLevel; j >= 0; j--) {
            // 内层循环枚举音量 
            if (a[i] + j <= maxLevel && f[i - 1][j]) {
                f[i][j + a[i]] = 1;
            }
            if (j - a[i] >= 0 && f[i - 1][j]) {
                f[i][j - a[i]] = 1;
            }
        } 
    }
    // 第一个f[n][i]==1的值即为最大值
    for (int i = maxLevel; i >= 0; i--) {
        if (f[n][i]) {
            printf("%d\n", i);
            return 0;
        }
    }
    printf("-1\n");

    return 0;
}
/*
input:
3 5 10               
5 3 7
output:
10
*/

希望我(菜鸟)的解析能对大家有bang'z

全部评论
给个赞呗!
点赞
送花
回复 分享
发布于 2021-08-30 21:54
第一个方法加个记忆化实际上就过去了😂
点赞
送花
回复 分享
发布于 2022-01-15 15:45
现代汽车中国前瞻数字研发中心
校招火热招聘中
官网直投

相关推荐

1 收藏 评论
分享
牛客网
牛客企业服务