砝码称重(超详细解析)

你有一架天平和 NN 个砝码,这 NN 个砝码重量依次是 W_1, W_2, · · · , W_NW1,W2,⋅⋅⋅,WN

请你计算一共可以称出多少种不同的重量? 注意砝码可以放在天平两边。

输入格式


输入的第一行包含一个整数 NN

第二行包含 NN 个整数:W_1, W_2, W_3, · · · , W_NW1,W2,W3,⋅⋅⋅,WN

输出格式


输出一个整数代表答案。

样例输入


3
1 4 6

样例输出


10

样例说明


能称出的 1010 种重量是:1、2、3、4、5、6、7、9、10、111、2、3、4、5、6、7、9、10、11。

1 = 1;1=1;

2 = 6 − 4 (2=6−4(天平一边放 66,另一边放 4);4);

3 = 4 − 1;3=4−1;

4 = 4;4=4;

5 = 6 − 1;5=6−1;

6 = 6;6=6;

7 = 1 + 6;7=1+6;

9 = 4 + 6 − 1;9=4+6−1;

10 = 4 + 6;10=4+6;

11 = 1 + 4 + 6。11=1+4+6。

评测用例规模与约定


对于 50%50的评测用例,1 ≤ N ≤ 151≤N≤15。

对于所有评测用例,1 ≤ N ≤ 100,N1≤N≤100,N个砝码总重不超过 100000100000。

运行限制

  • 最大运行时间:1s

  • 最大运行内存: 256M

#include 
#include 
#include 
//也是动态规划
//砝码重量
int main(int argc, char *argv[])
{
  int a[101][100001]={0};//最好初始化0
  //题设上限设空间
  int w[101];//用于存放单个砝码的重量
  a[0][0]=1;
  //相当于信标和必备条件,所有情况都必须建立在开始是两边为0的情况
  //将两边都链接起来
  int n,sum=0,ans=0,i;//sum,ans没有初始化!!!(细节扣分)
  scanf("%d",&n);
  for( i=1;i<=n;i++)
  {
    scanf("%d",&w[i]);
    sum+=w[i];//所有砝码重量的上限,用来检测循环上限。
  }
for(i=1;i<=n;i++)//砝码个数
//循环里面声明的i仅对循环里面有效
{
  for(int j=0;j<=sum;j++ )
  //sum作为上限,一一检索每一个重量的可能
  //以a[0][0]=1作为引导,不可能的重量一定赋值为0
  //这里j不能从1开始 必须从0 第一件物品不可能称出0 但是前i件可能称出0(两边重量相等时)
  //而且可能牵连到其他数值,反正多遍历一个也不吃亏
  {
    a[i][j]=a[i-1][j]+a[i-1][abs(j-w[i])]+a[i-1][j+w[i]];
    //     什么都不放       左边放            右边放
    //不用管这个加号,就是只要其中有一个那么目的就达成了,
    //我们的目的是为了探寻j下标点亮了多少个,
    //因为i是砝码,j是重量,目的就是为了看这个重量能不能成立。
    //      绝对值是因为负号只是代表方向,大小和正的是一样的
  }
}
//程序流程就是从1个砝码开始放,连接起0个砝码的情况(用信标),类推

 for(i=1;i<=sum;i++)
 //为何不能i=0?
 //题设示例本可以什么都不放测出重量0,但是示例中没有,说明不包含0重量
 {
   if(a[n][i])
   //直接到n是因为我们本来就是要统计最终有多少个上限重量的个数
   //前面的计算都把1-n都叠加起来了
   //就以情况为例子,最多情况就可能有所有砝码总重量这么多,因为其他组合都算重复了
   //题目要求是不重复的情况,我们用总重量作为循环上限,规避了重复的情况,也实现了全面遍历.
   //(有就加1,没有就不加,反正最多就是总重量这么多情况
   {
     ans++;

   }
 }
 printf("%d",ans);
  return 0;
}
//经验
//不会用重量上限规避重复,设置情况上限,复杂问题很难直接解决的一定要用动态规划
//动态规划就是:设置起点标记1
//2.后面与前面用题目情景连接(用式子)
//3.循环一定要逐个检索

你可能感兴趣的:(c语言)