AcWing 426. 开心的金明(0/1背包基础题)

题目描述
金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间他自己专用的很宽敞的房间。

更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过N元钱就行”。

今天一早金明就开始做预算,但是他想买的东西太多了,肯定会超过妈妈限定的N元。

于是,他把每件物品规定了一个重要度,分为5等:用整数1~5表示,第5等最重要。

他还从因特网上查到了每件物品的价格(都是整数元)。

他希望在不超过N元(可以等于N元)的前提下,使每件物品的价格与重要度的乘积的总和最大。

设第j件物品的价格为v[j],重要度为w[j],共选中了k件物品,编号依次为j1,j2,…,jk,则所求的总和为: 

v[j1]∗w[j1]+v[j2]∗w[j2]+…+v[jk]∗w[jk]

请你帮助金明设计一个满足要求的购物单。

输入格式
输入文件的第1行,为两个正整数N和m,用一个空格隔开。(其中N表示总钱数,m为希望购买物品的个数)

从第2行到第m+1行,第j行给出了编号为j-1的物品的基本数据,每行有2个非负整数v和p。(其中v表示该物品的价格,p表示该物品的重要度)

输出格式
输出文件只有一个正整数,为不超过总钱数的物品的价格与重要度乘积的总和的最大值(数据保证结果不超过100000000)。

数据范围
1≤N<30000,
1≤m<25,
0≤v≤10000,
1≤p≤5

输入样例:

1000 5
800 2
400 5
300 5
400 3
200 2

输出样例:

3900

思路

这是简单的0/1背包问题

一开始的思路有一些错误,题目要求是“使每件物品的价格与重要度的乘积的总和最大”,但是我理解成在价格相同时重要程度需要更大,在重要程度相同时价格需要更小,同时保证两者的乘积总和最大,把题目给复杂化了。

其实只需要在保证总价格不超过所给的条件下
让“价格*重要度=价值”并使之最大化即可。

动态规划使用闫式Dp法:
在这里插入图片描述
f[i, j]存的是如下数据

i\j 0 1 2 3 4 5 m
1 当总钱数为0时只取第一个物品的最大价值 当总钱数为m时只取第一个物品的最大价值
2 当总钱数为0时取前两个物品的最大价值 当总钱数为m时取前两个物品的最大价值
3
4
5 当总钱数为0时取前五个物品的最大价值

j:表示当前可以取的总钱数。每当新取一个物品时,如果要买这个物品,那么当前可以取得总钱数都要从0遍历到最大总钱数N(代码中最大总钱数用m表示),看每一个总钱数的状态下的最大价值存入f[i, j]。

0/1背包问题思考的方式:
题目:一共有i个物品,放入体积为V的书包中,要保证放入的物品总体积不超过书包的体积,且质量最大,给了每个物品的体积和密度。
思路:每放入一个物品,都考虑一次前i个物品的放入方式
保证:体积不超过书包体积V的条件下,取到的最大价值

0/1背包问题相比:

0/1背包 购物
每个物品的体积 每个物品的价格
密度 重要性等级
质量(体积*密度) 价值(价格*等级)
取得最大值:质量最大 取得最大值:价值最大
条件:不超过给定体积 条件:不超过总钱数

AC代码

#include <iostream>
#include <algorithm>

using namespace std;

/*
这道题跟0/1背包的思路一模一样,
顺便复习了动态规划的基本思路
*/

const int N = 30010, M = 30;

int n, m;//n购买物品个数、m总钱数
int v, w;//v物品单价、w物品等级
int f[M][N];//M购买物品个数最大范围、N总钱数最大范围、f存最大价值

int main()
{
    
    
    cin >> m >> n;
    for(int i = 1; i <= n; i ++){
    
    //所以时间复杂度O(n*m)
        cin >> v >> w;
        w = w * v;//w物品的价值
        for(int j = 0; j <= m; j ++){
    
    //总价钱从0到m遍历
            f[i][j] = f[i - 1][j];//不取这个物品
            if(j >= v)//一开始漏掉了这个条件,当前总钱数买得起这个物品:才可以取这个物品
                f[i][j] = max(f[i][j], f[i - 1][j - v] + w);//取这个物品
            //f[i - 1][j - v] + w代表取这个物品后
            //剩下的钱可以买不取这个物品时的1到(i-1)物品的最大价值
        }
    }

    cout << f[n][m] << endl;

    return 0;
}

大雪菜的代码:
在这里插入图片描述
大雪菜的优化:
在这里插入图片描述

以上部分内容是自己整理的,如有误,欢迎指正
今日刷题量1/2

猜你喜欢

转载自blog.csdn.net/weixin_43232564/article/details/113632138