挂饰题解

题目:

OI君有N个装在手机上的挂饰,编号为1…N。 JOI君可以将其中的一些装在手机上。
JOI君的挂饰有一些与众不同——其中的一些挂饰附有可以挂其他挂件的挂钩。每个挂件要么直接挂在手机上,要么挂在其他挂件的挂钩上。直接挂在手机上的挂件最多有1个。
此外,每个挂件有一个安装时会获得的喜悦值,用一个整数来表示。如果JOI君很讨厌某个挂饰,那么这个挂饰的喜悦值就是一个负数。
JOI君想要最大化所有挂饰的喜悦值之和。注意不必要将所有的挂钩都挂上挂饰,而且一个都不挂也是可以的。

分析:

1.状态:

dp[i][j]表示已经挂好了前i个挂饰还有j个挂钩

2.状态转移方程:

dp[i][j] = max(不放第i个, 放了第i个再加上当前第i个的魅力值)

3.具体实现:

首先要排个序,将挂钩多的挂饰先挂(尽可能加大可以挂的空间),然后想到这,可能有的人会直接一个三重暴力枚举,但是显然这是不行的,我们需要更少的时间。但是如果把程序优化到二维,那么此时就要考虑如何求得当前的挂钩数了,方法很多,这里提几个:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
int n, dp[2005][4010], _max = -1000000005;
struct jj {
    int a, b;
} c[2005];
int cmp(jj x, jj y) { return x.a > y.a; }
int main() {
    memset(dp, -0x7f7f7f7f, sizeof(dp));
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        scanf("%d %d", &c[i].a, &c[i].b);
    }
    for (int i = 0; i <= n; i++) {
        for (int j = 0; j <= 2 * n; j++) {
            dp[i][j] = -2100000000;
        }
    }
    dp[0][1] = 0;
    sort(c + 1, c + 1 + n, cmp);
    for (int i = 1; i <= n; i++) {
        for (int j = 0; j <= 2 * n; j++) {//应为若考虑极端那么最多就是两个挂钩数量为n的挂在一起所以最多2*n个钩子
            if (j > 0) {
                dp[i][j - 1 + c[i].a] = max(dp[i - 1][j] + c[i].b, dp[i - 1][j - 1 + c[i].a]);
                //将每个dp[i][j]取第i个的情况提前计算出来
                dp[i][j] = max(dp[i - 1][j], dp[i][j]);
            } else {
                dp[i][j] = max(dp[i - 1][j], dp[i][j]);
            }
        }
    }
    for (int i = 0; i <= 2 * n; i++) {
        if (dp[n][i] > _max) {
            _max = dp[n][i];
        }
    }
    printf("%d", _max);
    return 0;
}
/*5
0 4
2 -2
1 -1
0 1
0 3*/

猜你喜欢

转载自blog.csdn.net/cqbz_lipengcheng/article/details/106877410