华为机试题-购物单

欢迎大家验证、留言、讨论!

链接:
问题链接
题目描述
王强今天很开心,公司发给N元的年终奖。王强决定把年终奖用于购物,他把想买的物品分为两类:主件与附件,附件是从属于某个主件的,下表就是一些主件与附件的例子:

主件 附件
电脑 打印机,扫描仪
书柜 图书
书桌 台灯,文具
工作椅 无

如果要买归类为附件的物品,必须先买该附件所属的主件。每个主件可以有 0 个、 1 个或 2 个附件。附件不再有从属于自己的附件。王强想买的东西很多,为了不超出预算,他把每件物品规定了一个重要度,分为 5 等:用整数 1 ~ 5 表示,第 5 等最重要。他还从因特网上查到了每件物品的价格(都是 10 元的整数倍)。他希望在不超过 N 元(可以等于 N 元)的前提下,使每件物品的价格与重要度的乘积的总和最大。
设第 j 件物品的价格为 v[j] ,重要度为 w[j] ,共选中了 k 件物品,编号依次为 j 1 , j 2 ,……, j k ,则所求的总和为:
v[j 1 ]*w[j 1 ]+v[j 2 ]*w[j 2 ]+ … +v[j k ]*w[j k ] 。(其中 * 为乘号)
请你帮助王强设计一个满足要求的购物单。

输入描述:

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

从第 2 行到第 m+1 行,第 j 行给出了编号为 j-1 的物品的基本数据,每行有 3 个非负整数 v p q

(其中 v 表示该物品的价格( v<10000 ), p 表示该物品的重要度( 1 ~ 5 ), q 表示该物品是主件还是附件。如果 q=0 ,表示该物品为主件,如果 q>0 ,表示该物品为附件, q 是所属主件的编号)

输出描述:

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

示例1
输入

1000 5
800 2 0
400 5 1
300 5 1
400 3 0
500 2 0

输出

2200

——————————————————————————————————————

问题描述没有说不能购买同一个物品,而且从别人写的通过的代码来看,它是可以多次选择同一个物品购买的,如下面的例子。

写了好久,改了好久,没有人觉得这道题有问题嘛!
———————————————————————————————
输入:
30 4
10 5 4
10 5 4
10 5 0
10 1 0

拿别人通过的代码测试,答案是110!!!!!不应该是150么! 3105=150 ,不对?
110=10* 5* 2+10* 1
150=10* 5* 3
————————————————————————————————
输入:
1000 5
800 2 0
400 5 1
300 5 1
400 3 0
500 2 0

给的答案是2200,不应该是2400么???
2200=500* 2+400* 3 (花了900块)
2400=2* 400 *3 (花了800块)

————————————————————————————————
后面附上自己的理解、解题过程和c++代码!

解题思路:先不要理附件的问题。
最后一步:选择了物品j,在小于等于i元的情况下,得到的权值f[i]最大。
子问题:在小于i-val[j]元的情况下,使得到的权值f[i-val[j]]最大。
目标:在小于等于i元的情况下,得到的权值f[i]最大。
可以进一步写出数学公式:
f ( i ) = m a x ( f ( i − v a l j ) + w j ) f(i)=max{(f(i-val_j)+w_j)} f(i)=max(f(ivalj)+wj)
w j = v a l j ∗ p j w_j=val_j*p_j wj=valjpj
i 是 奖 金 数 、 f ( i ) 是 权 值 就 是 价 格 ∗ 重 要 度 的 总 和 , v j 是 物 品 j 的 价 格 , i是奖金数、f(i)是权值就是价格*重要度的总和,v_j是物品j的价格, if(i)vjj
w j 是 物 品 j 的 权 值 、 p j 是 物 品 j 的 重 要 度 w_j是物品j的权值、p_j是物品j的重要度 wjjpjj

我将输入的数据划分保存,val数组的保存主、附件的价格;w数组保存对应的重要度。

考虑附件可以选择的情况,总共有四种(因为最多两个附件):
1、只选择主件 (i要大于主件对应的价格)
2、主+附件1
3、主+附件2 (i要大于主件对应的价格+附件2的价格)
4、主+附件1+附件2

因为必须先选择主件才能选择附件,所以选择时,金钱数应大于对应项。

#include<iostream>
using namespace std;

int main()
{
    int N,m,cost,sum;
    cin>>N>>m;
    N/=10;
    int val[m][3]={0},w[m][3]={0};//初始化为0
    int v,p,q;
    int f[N+1]={0};

    for(int i=0;i<m;i++)
    {
        cin>>v>>p>>q;
        v/=10;
        if(q==0) val[i][0]=v, w[i][0]=v*p;//val的第1列存主件的价格,w存重要程度*价格
        else
        {
            if(val[q-1][1]==0) val[q-1][1]=v, w[q-1][1]=v*p;//val的第2列存附件1的价格
            else val[q-1][2]=v, w[q-1][2]=v*p;//val的第2列存附件2的价格
        }
    }
    
    for(int i=0;i<=N;i++)
    {
        for(int j=0;j<m;j++)
        {
            if(i>=val[j][0]) f[i]=max(f[i-val[j][0]]+w[j][0],f[i]);
            if(i>=(val[j][0]+val[j][1])) f[i]=max(f[i-val[j][0]-val[j][1]]+w[j][0]+w[j][1],f[i]);
            if(i>=(val[j][0]+val[j][2])) f[i]=max(f[i-val[j][0]-val[j][2]]+w[j][0]+w[j][2],f[i]);
            if(i>=(val[j][0]+val[j][1]+val[j][2])) f[i]=\
            max(f[i-val[j][0]-val[j][1]-val[j][2]]+w[j][0]+w[j][1]+w[j][2],f[i]);
        }
    }
    cout<<f[N]*10;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值