题目描述
思路
- 借鉴了y总的思路点这里看思路
- 状态表示:f[i][j]的意义是i个砝码能称出重量为j的方案的集合,属性:f[i][j]为1或0,为1说明前i个砝码可以称出重量j
- 状态计算:可以将第i个物品分为三种状态,(放在左边,不放,放在右边)其中任何一种状态存在则f[i][j]存在
- 注意j的取值范围(-sum(全部放在左边)到sum(全部放在右边)),又因为j还是数组下标,所以j不能为负,所以在使用下标为j时要加sum使下标为正
- 结果表示f[n][j](j取值范围为1-sum)j取值范围为1-sum原因:0能称出来,但是不应该算一种,所以j从1开始,又因为称出来的正负重量是对称的(放在左边1,放在右边4、6,能称出来9,同理放在右边1,放在左边4、6,也能称出来9,但是计数的时候记了两次)所以遍历正数这边即可
代码
#include<stdio.h>
int f[110][100100];
int w[110];//存储各砝码的重量
int main(){
int n,i,j;
int count=0,sum=0;//存储个数与砝码和
scanf("%d",&n);
for(i=1;i<=n;i++){
scanf("%d",&w[i]);
sum+=w[i];
}//读入数据并求出砝码和
f[0][sum]=1;//!!!!f[0][0]为1,因为下标都加上了sum,所以f[0][sum]=1!!!很重要
for(i=1;i<=n;i++){
for(j=-sum;j<=sum;j++){//注意j的取值范围
f[i][j+sum]=f[i-1][j+sum];//不放砝码i
if(j+sum-w[i]>=0)f[i][j+sum] =f[i-1][j+sum-w[i]] || f[i][j+sum];//i放在右侧
if(j+sum+w[i]<=2*sum)f[i][j+sum]= f[i-1][j+sum+w[i]] || f[i][j+sum];//i放在左侧
}
}
for(j=1;j<=sum;j++){//注意循环起点与终点
if(f[n][j])count++;
}
printf("%d",count);
return 0;
}