动态规划——砝码称重

问题描述:

设有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. 1 #include <iostream>  
  2.  2 using namespace std;  
  3.  3 #define N 6  
  4.  4 #define M 1000  
  5.  5 int w[N]={1,2,3,5,10,20};  
  6.  6 int c[N]={0};  
  7.  7 int visit[M+1] = {0};  
  8.  8   
  9.  9 int weight_count()  
  10. 10 {  
  11. 11         int i = 0;  
  12. 12         int j = 0;  
  13. 13         int total = 0;  
  14. 14         int count =0;  
  15. 15   
  16. 16         visit[0] = w[0]*c[0];//visit[0]用于每添加一个砝码时遍历的结束位置  
  17. 17         for(i = 1;i<=c[0];i++)  
  18. 18                 visit[w[0]*i] = 1;//初始化visit[1~c[0]],表示已经添加了砝码1  
  19. 19         for(i = 1;i<N;i++)  
  20. 20         {  
  21. 21                 int m = visit[0];  
  22. 22                 for(int k = 1;k<=c[i];k++)  
  23. 23                 {  
  24. 24                         for(j = 0;j<=m;j++)  
  25. 25                         {  
  26. 26                                 if(j+ k*w[i]>M)  
  27. 27                                         break;  
  28. 28                                  if(visit[j] == 1 && visit[j + k*w[i]] != 1 || j==0)  
  29. 29                                  {  
  30. 30                                         visit[j + k*w[i]] = 1;  
  31. 31                                         total = j+k*w[i];  
  32. 32                                  }  
  33. 33                         }  
  34. 34                 }  
  35. 35                 visit[0] = total;  
  36. 36         }  
  37. 37         for(i = 1;i<=M;i++)  
  38. 38         {  
  39. 39                 if(visit[i]==1)  
  40. 40                 {  
  41. 41                         cout << i << " ";  
  42. 42                         count ++;  
  43. 43                 }  
  44. 44         }  
  45. 45         return count;  
  46. 46   
  47. 47 }  
  48. 48 int main()  
  49. 49 {  
  50. 50         int i = 0;  
  51. 51         for(i = 0;i<N;i++)  
  52. 52                 cin >>c[i];  
  53. 53         int count = weight_count();  
  54. 54         cout << count << endl;  
  55. 55 }  

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值