资源限制
时间限制:1.0s 内存限制:256.0MB
问题描述
金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间他自己专用的很宽敞的房间。更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎 么布置,你说了算,只要不超过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(<30000)表示总钱 数,m(<25)为希望购买物品的个数。)
从第2行到第m+1行,第j行给出了编号为j-1的物品的基本数据,每行有2个非负整数
v p
(其中v表示该物品的价格(v<=10000),p表示该物品的重要度(1~5))
输出格式
输出文件只有一个正整数,为不超过总钱数的物品的价格与重要度乘积的总和的最大值(<100000000)。
样例输入
1000 5
800 2
400 5
300 5
400 3
200 2
样例输出
3900
思考:01背包问题,注意的点就是:在普通物品表上加一栏用来存储加权值,也就是重要度和价格的乘积,建立两张表,一张用来判断费用,一张用来对应存储加权值。因为有两张表,所以要同时对两张表进行操作,最后输出的是加权值表中的最后一项。还有一点就是,判断继续装包还是不装包的判断时,要根据加权值的大小进行判断,而不能用计费表中的值进行判断,因为计费表中的值越大代表剩余的费用越少,这就与我们的目的相悖。
//01背包问题
import java.util.*;
public class Main {
public static void main(String [] args) {
Scanner in=new Scanner(System.in);
int N ,m;
N=in.nextInt();//可以支配的总钱数
m=in.nextInt();//预采购数量
int[][] list=new int[m+1][4];//价格,重要度,加权值表
int[][] cap=new int[m+1][N+1];//背包容量表
int[][] res=new int[m+1][N+1];//结果表存放加权值
for(int i=1;i<m+1;i++)//输入价格表
{
for (int j=1;j<3;j++)
{
list[i][j]=in.nextInt();//按照题目要求输入,第一列为价格,第二列为重要度
}
}
for(int i=1;i<m+1;i++)//将加权之后的值记录进list的最后一列中
{
list[i][3]=list[i][1]*list[i][2];//价格和重要度相乘
}
for (int i=1;i<m+1;i++)//商品从第一个开始
{
for(int j=1;j<N+1;j++)//可承受价格从1开始递增
{
if(list[i][1]>j)//如果此时的商品价格超过可承受价格,则不进行购买,加权值等顺延上一个
{
cap[i][j]=cap[i-1][j];
res[i][j]=res[i-1][j];
}
else
{
int value1=cap[i-1][j-list[i][1]]+list[i][1];//价格可以承受且继续购买物品
int res1=res[i-1][j-list[i][1]]+list[i][3];//同上
int value2=cap[i-1][j];//不在购买物品
int res2=res[i-1][j];//同上
if(res1>res2)//注意!!!要比较加权值的大小,使用加权值大的那一个
{
cap[i][j]=value1;
res[i][j]=res1;
}
else
{
res[i][j]=res2;
cap[i][j]=value2;
}
}
}
}
System.out.println(res[m][N]);//输出最后一个加权值,也就是在限额下最后一个商品执行完操作后的值
}
}