描述
现有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;
}