华为机试题41-称砝码

描述

现有n种砝码,重量互不相等,分别为 m1,m2,m3…mn ;
每种砝码对应的数量为 x1,x2,x3...xn 。现在要用这些砝码去称物体的重量(放在同一侧),问能称出多少种不同的重量。

注:

称重重量包括 0

数据范围:每组输入数据满足 1≤n≤10 , 1≤mi​≤2000 , 1≤xi​≤10

输入描述:

对于每组测试数据:
第一行:n --- 砝码的种数(范围[1,10])
第二行:m1 m2 m3 ... mn --- 每种砝码的重量(范围[1,2000])
第三行:x1 x2 x3 .... xn --- 每种砝码对应的数量(范围[1,10])

输出描述:

利用给定的砝码可以称出的不同的重量数

示例1

输入:

2
1 2
2 1

输出:

5

说明:

可以表示出0,1,2,3,4五种重量。


这道题有一定的难度。



解题思路:

我们可以这么看,比如只有1种砝码,重量是1,共有3个;在加入砝码前,可称的重量只有1种,即{0},现在加入1个砝码,总共可达的重量有{0,0+1},这个0是原来可达的重量,继承下来,0+1表示的是,原来重量加上新砝码之后的重量;现在再加1个砝码,可达的重量有{0,0+1,0+1,0+1+1},红色字体重量为新增砝码后可达的重量,去重复后可达的重量有{0,1,2},那么我们该怎么去重,或者说每加入一个砝码,避免产生重复的重量。

可以这样,我们定义一个足够大的整型数组(此处足够大,表示数组下标应不小于所有砝码可称的最大重量),数组下标表示可称重量,数组元素值为0表示达不到这个重量,为1表示这个重量可以称到,比如arr[4]=1,就表示这些砝码能够称出重量为4的重量,如果arr[6]=0,则表示重量为6用砝码称不出来;由于0也是一种重量,所以arr[0]=1。

最关键的一步,我们每加入一个砝码前,先遍历arr数组,比如新加入的砝码重量为3,且arr[4]=1,我们可知原来的砝码可达4的重量,那么再加入重量为3的砝码,可达的重量就是7,令arr[7]=1,做好标记。需要注意,遍历arr数组时应该从后往前遍历,如若从前往后遍历,还是刚才那个例子,同一个砝码,遍历到arr[7]的时候发现是1,又会得到arr[10]=1,实际上arr[7]原来可能是0,是因为arr[4]=1,再加上重量为3的砝码后才有的arr[7]为1,那这样就会导致给arr[10]赋值为1就是错的,因为加入重量为3的砝码之前,可能根本没能达到重量为7;从后往前遍历就不会有这个问题,这里大家可以思考一下为什么。

了解清楚后,写代码就比较简单了。

#include <stdio.h>
#define    N    200000
int main()
{
    int arr[N]={1};    //arr数组用于记录能够组成的重量,下标为重量,数值1代表能达到
    int n,m[10],x[10],i,j,k,sum=0,cnt=0;
    scanf("%d",&n);
    for(i=0;i<n;i++)
        scanf("%d",&m[i]);
    for(i=0;i<n;i++)
        scanf("%d",&x[i]);
    for(i=0;i<n;i++)
        sum+=m[i]*x[i];
    for(i=0;i<n;i++)        //遍历每一种砝码
    {
        for(j=0;j<x[i];j++)    //遍历这种砝码的每一个砝码
        {
            for(k=sum;k>=0;k--)        //重量从后往前遍历
            {
                if(arr[k])            //原来可达重量为k
                    arr[k+m[i]]=1;        //加入新砝码后可达的重量为k+m[i]
            }
        }
    }
    for(i=0;i<=sum;i++)
        if(arr[i])         //arr[i]为1,表示能达到重量i,每有一个元素为1,可表示的重量加1
            cnt++;
    printf("%d\n",cnt);
    return 0;
}

  • 6
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值