问题描述:
设有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的个数就得到不同重量的个数。
通过这个辅助数组,就可以除去重复情况,实现如下:
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 }