问题描述:
设有1g,2g,3g,5g,10g,20g的砝码各若干枚(其总重≤1000g),要求:
输入:
a1 a2 a3 a4 a5 a6(表示1g砝码有a1个,2g砝码有a2个,......20g砝码有a6个)
输出:
Total=N (N表示用这些砝码能称出的不同重量的个数,但不包括一个砝码也不用的情况)
输入样例:1 1 0 0 0 0
输出样例:Total=3,表示可以称出1g,2g,3g三种不同的重量
动态规划求解:
从砝码1开始分析,假设前i个砝码能称出的不同重量为Q[i],那么Q[i]一定是这样计算出来的:在Q[i-1]的基础上,对Q[i-1]个不同的重量,分别添加k个砝码i,再添加的过程中除去重复情况。
假设:w[N]表示N个不同重量的砝码(例子中N=6),w[0~N-1]。
c[N]表示N个不同砝码相应的数量,c[1~N]。
则:Q[i] = (Q[i-1] + k*w[i])-添加过程中重复的个数。其中0=<k<=c[i]。
定义一个辅助布尔型数组visit[M+1],这里的M是例子中的1000,表示最大重量不超过M。
visit[j]=1表示,重量为j的情况已经存在,否则表示重量为j的情况还未出现。其中visit[0]作为一个多余空间存在,可以作为一个临时变量。最后遍历visit[1~M],统计1的个数就得到不同重量的个数。
通过这个辅助数组,就可以除去重复情况,实现如下:
[cpp]
view plain
copy
- 1 #include <iostream>
- 2 using namespace std;
- 3 #define N 6
- 4 #define M 1000
- 5 int w[N]={1,2,3,5,10,20};
- 6 int c[N]={0};
- 7 int visit[M+1] = {0};
- 8
- 9 int weight_count()
- 10 {
- 11 int i = 0;
- 12 int j = 0;
- 13 int total = 0;
- 14 int count =0;
- 15
- 16 visit[0] = w[0]*c[0];//visit[0]用于每添加一个砝码时遍历的结束位置
- 17 for(i = 1;i<=c[0];i++)
- 18 visit[w[0]*i] = 1;//初始化visit[1~c[0]],表示已经添加了砝码1
- 19 for(i = 1;i<N;i++)
- 20 {
- 21 int m = visit[0];
- 22 for(int k = 1;k<=c[i];k++)
- 23 {
- 24 for(j = 0;j<=m;j++)
- 25 {
- 26 if(j+ k*w[i]>M)
- 27 break;
- 28 if(visit[j] == 1 && visit[j + k*w[i]] != 1 || j==0)
- 29 {
- 30 visit[j + k*w[i]] = 1;
- 31 total = j+k*w[i];
- 32 }
- 33 }
- 34 }
- 35 visit[0] = total;
- 36 }
- 37 for(i = 1;i<=M;i++)
- 38 {
- 39 if(visit[i]==1)
- 40 {
- 41 cout << i << " ";
- 42 count ++;
- 43 }
- 44 }
- 45 return count;
- 46
- 47 }
- 48 int main()
- 49 {
- 50 int i = 0;
- 51 for(i = 0;i<N;i++)
- 52 cin >>c[i];
- 53 int count = weight_count();
- 54 cout << count << endl;
- 55 }