题目描述
金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间他自己专用的很宽敞的房间。
更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过N元钱就行”。
今天一早金明就开始做预算,但是他想买的东西太多了,肯定会超过妈妈限定的N元。
于是,他把每件物品规定了一个重要度,分为5等:用整数1~5表示,第5等最重要。
他还从因特网上查到了每件物品的价格(都是整数元)。
他希望在不超过N元(可以等于N元)的前提下,使每件物品的价格与重要度的乘积的总和最大。
设第j件物品的价格为v[j],重要度为w[j],共选中了k件物品,编号依次为j1,j2,…,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