题目描述
金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间他自己专用的很宽敞的房间。更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过 N N N元钱就行”。今天一早金明就开始做预算,但是他想买的东西太多了,肯定会超过妈妈限定的 N N N元。于是,他把每件物品规定了一个重要度,分为 5 5 5等:用整数 1 − 5 1-5 1−5表示,第 5 5 5等最重要。他还从因特网上查到了每件物品的价格(都是整数元)。他希望在不超过 N N N元(可以等于 N N N元)的前提下,使每件物品的价格与重要度的乘积的总和最大。
设第 j j j件物品的价格为 v [ j ] v[j] v[j],重要度为 w [ j ] w[j] w[j],共选中了 k k k件物品,编号依次为 j 1 , j 2 , … , j k j_1,j_2,…,j_k j1,j2,…,jk,则所求的总和为:
v [ j 1 ] × w [ j 1 ] + v [ j 2 ] × w [ j 2 ] + … + v [ j k ] × w [ j k ] v[j_1] \times w[j_1]+v[j_2] \times w[j_2]+ …+v[j_k] \times w[j_k] v[j1]×w[j1]+v[j2]×w[j2]+…+v[jk]×w[jk]。
请你帮助金明设计一个满足要求的购物单。
输入格式
第一行,为 2 2 2个正整数,用一个空格隔开: n , m n,m n,m(其中 N ( < 30000 ) N(<30000) N(<30000)表示总钱数, m ( < 25 ) m(<25) m(<25)为希望购买物品的个数。)
从第 2 2 2行到第 m + 1 m+1 m+1行,第 j j j行给出了编号为 j − 1 j-1 j−1的物品的基本数据,每行有 2 2 2个非负整数$ v p (其中 (其中 (其中v 表示该物品的价格 表示该物品的价格 表示该物品的价格(v \le 10000) , , ,p$表示该物品的重要度( 1 − 5 1-5 1−5)
输出格式
1 1 1个正整数,为不超过总钱数的物品的价格与重要度乘积的总和的最大值 ( < 100000000 ) (<100000000) (<100000000)。
样例 #1
样例输入 #1
1000 5
800 2
400 5
300 5
400 3
200 2
样例输出 #1
3900
题解
背包问题主要是背模板,这里收录了一些模板
一些复杂的背包问题(如泛化物品)未收录
01背包问题:
无优化
for(int i=1;i<=n;i++)
{
for(int c=0;c<=m;c++)
{
f[i][c]=f[i-1][c];
if(c>=w[i])
f[i][c]=max(f[i][c],f[i-1][c-w[i]]+v[i]);
}
}
一维数组优化:
for(int i=1;i<=n;i++)
{
for(int c=m;c>=0;c--)
{
if(c>=w[i])
f[c]=max(f[c],f[c-w[i]]+v[i]);
}
}
更进一步的常数优化:
for(int i=1;i<=n;i++)
{
sumw+=w[i];
bound=max(m-sumw,w[i]);
for(int c=m;c>=bound;c--)
{
if(c>=w[i])
f[c]=max(f[c],f[c-w[i]]+v[i]);
}
}
完全背包问题:
for(int i=1;i<=n;i++)
{
for(int c=0;c<=m;c++)
{
if(c>=w[i])
f[c]=max(f[c],f[c-w[i]]+v[i]);
}
}
多重背包问题:
for(int i=1;i<=n;i++)
{
if(w[i]*a[i]>m)
{
for(int c=0;c<=m;c++)
{
if(c>=w[i])
f[c]=max(f[c],f[c-w[i]]+v[i]);
}
}
else
{
k=1;amount=a[i];
while(k<amount)
{
for(int c=k*w[i];c>=0;c--)
{
if(c>=w[i])
f[c]=max(f[c],f[c-w[i]]+k*v[i]);
}
amount-=k;
k<<=1;
}
for(int c=amount*w[i];c>=0;c--)
{
f[c]=max(f[c],f[c-w[i]]+amount*v[i]);
}
}
}
下面来到我们的正题: 首先判断是否为背包问题,可见其背包就是money的总数,质量就是重要度*money
可以套用背包问题
有根据其特性可知这是01背包
到此建模完成,思考+读题用时3min
c++代码:
#include<iostream>
#include<algorithm>
using namespace std;
int want[30],monny[30],dp[50000];//want数组为重要度,monny数组为money,dp是用来dp的数组
int wantbuy,ansmonny;//wantbuy是总物品个数,ansmonny是总钱数
int main()
{
cin>>ansmonny>>wantbuy;//输入
for(int i=1;i<=wantbuy;i++)
{
cin>>monny[i]>>want[i];
want[i]*=monny[i];//want数组在这里意义变为总收获(重要度*money)
}
//01背包(参照第二类模板“一维数组优化”)
for(int i=1;i<=wantbuy;i++)
{
for(int j=ansmonny;j>=monny[i];j--)//注意从ansmonny开始
{
if(j>=monny[i])
{
dp[j]=max(dp[j],dp[j-monny[i]]+want[i]);//dp
}
}
}
cout<<dp[ansmonny]<<endl;//背包大小为ansmonny时最大值
return 0;
}