zoukankan      html  css  js  c++  java
  • dp背包问题/01背包,完全背包,多重背包,/coin change算法求花硬币的种类数

    一步一步循序渐进。

    Coin Change

    具体思想:给你 N元,然后你有几种零钱S={S1,S2...,Sm} (每种零钱数量不限).

    问:凑成N有多少种组合方式  即N=x1 * S1+x2*S2+...+xk*Sk (xk>=0,k=1,2..m) 

    设有f(x)中组合方式   

    有两种解答(自底向上回溯):  1.不用第m种货币   f(N,m-1)

                    2.用第m种货币 f(N-Sm,m) 

                    总的组合方式为f(N,m)=f(N,m-1)+f(N-Sm,m)

    anything is nonsense,show me the code

    1 def count( n, m ):
    2     if n < 0 or m <= 0: #m < 0 for zero indexed programming languages
    3         return 0
    4     if n == 0: # needs be checked after n & m, as if n = 0 and m < 0 then it would return 1, which should not be the case.
    5         return 1
    6  
    7     return count( n, m - 1 ) + count( n - S[m], m )

    ----------------------------------

    因为f(N,m)<f(x,y)  <--> n<=x,m<=y  (n,m)!=(x,y).因此满足dp的最优子结构条件

    时间复杂度会有O(n*m)

    详解和用树的思想分析符合dp

     1 func count( n, m )
     2 
     3   for i from 0 to n
     4     for j from 0 to m
     5       if i equals 0
     6          table[i, j] = 1          
     7       else if j equals 0
     8          table[i, j] = 1 if i%S[j] equals 0 else 0
     9       else if S_j greater than i
    10          table[i, j] = table[i, j - 1]
    11       else 
    12          table[i, j] = table[i - S_j, j] + table[i, j-1]
    13 
    14   return table[n, m]

    三道题目练手:

    UVA,674

              

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 using namespace std;
     5 
     6 int S[5]={1,5,10,25,50};
     7 
     8 int count(int n)
     9 {
    10     int table[n+1];
    11     memset(table,0,sizeof(table));
    12     
    13     table[0]=1;
    14     for(int i=0;i<5;i++)
    15         for(int j=S[i];j<=n;j++)
    16             table[j]+=table[j-S[i]];
    17     return table[n];
    18 }
    19 
    20 int main()
    21 {
    22     int n;
    23     while(~scanf("%d",&n))
    24     {
    25         printf("%d
    ",count(n));
    26     }
    27     return 0;
    28 }

    UVA,147

    注意点:存在小数,又因为题目提示都是5的倍数,所以每项乘以100作整数处理

    .......这题我想砸电脑。。我5000/5=1250....wa 十几分钟。

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <string.h>
     5 using namespace std;
     6 
     7 int S[11]={1,2,4,10,20,40,100,200,400,1000,2000};
     8 
     9 int main()
    10 {
    11     long long table[6010]={1};
    12     for(int i=0;i<11;i++)
    13         for(int j=S[i];j<=6000;j++)
    14             table[j]+=table[j-S[i]];
    15     double n;
    16     while(scanf("%lf",&n)!=EOF)
    17     {
    18         int c=(int)(n*20+0.5);
    19         if(n==0.00)
    20             break;
    21         printf("%6.2lf%17lld
    ",n,table[c]);
    22     }
    23     return 0;
    24 }

    UVA, 357

    用long long表示组合的的种类比较多

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 using namespace std;
     5 
     6 int S[5]={1,5,10,25,50};
     7 const int maxn=30010;
     8 //水题
     9 int main()
    10 {
    11     int n;
    12     long long table[maxn];
    13     memset(table,0,sizeof(table));
    14     table[0]=1;
    15     for(int i=0;i<5;i++)
    16         for(int j=S[i];j<=maxn;j++)
    17             table[j]+=table[j-S[i]];
    18     while(~scanf("%d",&n))
    19     {
    20         if(table[n]==1)
    21             printf("There is only 1 way to produce %d cents change.
    ",n);
    22         else
    23             printf("There are %lld ways to produce %d cents change.
    ",table[n],n);
    24     }
    25     return 0;
    26 }

    ----------------------------------

    动态规划具体详解:动态规划,从新手到专家

    背包问题:背包问题九

    uva,357

    题意是买东西问题,生活中最常见的问题竟然弄这么道题目,真是开眼界了。

    给你一组货币 {5c,10c,20c,50c,1,2} 

    输入:每种货币的个数,需要付的钱

    条件:售货员有每种货币充足,你每种货币数量已知,要你求付钱所用最少的硬币数量(最优子结构)

    模拟背包:需要付的钱为背包容量,每种货币为要装进背包的容量,

    所有的硬币数=我付的硬币数+售货员找我的硬币数(最小)

    用两部分的最小达到总体的最小(局部最优解求总体最优解)

    满足以上两个要素为dp问题。

    完全背包:售货员硬币足够。 用它算出售货员要找的硬币的最小个数

    多重背包:我要付的硬币的最小个数

     1 #include <cstdio>
     2 #include <string.h>
     3 #include <math.h>
     4 
     5 using namespace std;
     6 
     7 const int MAX=2000;
     8 int coin[6]={1,2,4,10,20,40},f1[MAX+1],f2[MAX+1],n[6];
     9 
    10 void zero_one(int *f,int t)
    11 {
    12     for(int i=MAX;i>=t;i--)
    13         if(f[i-t]!=-1 && (f[i]==-1 || f[i-t]+1<f[i]))
    14             f[i]=f[i-t]+1;
    15 }
    16 
    17 void complete(int *f,int t)
    18 {
    19     for(int i=t;i<=MAX;i++)
    20         if(f[i-t]!=-1 && (f[i]==-1 || f[i-t]+1<f[i]))
    21             f[i]=f[i-t]+1;
    22 }
    23 
    24 void multiple(int *f)
    25 {
    26     for(int i=0;i<6;i++)
    27         if(n[i]*coin[i]>MAX)
    28             complete(f,coin[i]);
    29         else
    30         {
    31             while(n[i]--)
    32                 zero_one(f,coin[i]);
    33         }
    34 }
    35 
    36 int main()
    37 {
    38     float t;
    39     int total;
    40     while(true)
    41     {
    42         total=0;
    43         for(int i=0;i<6;i++)
    44         {
    45             scanf("%d",&n[i]);
    46             total+=n[i];
    47         }
    48         if(total==0)
    49             break;
    50         scanf("%f",&t);
    51         int tar=(int)(t*20+0.5f);
    52         memset(f1,-1,sizeof(f1));f1[0]=0;
    53         memset(f2,-1,sizeof(f2));f2[0]=0;
    54         
    55         multiple(f1);
    56         
    57         for(int i=0;i<6;i++)
    58             complete(f2,coin[i]);
    59         int ans=MAX;
    60         
    61         for(int i=tar;i<=MAX;i++)
    62         {
    63             if(f1[i]!=-1 && f2[i-tar]!=-1 && ans>f1[i]+f2[i-tar])
    64                 ans=f1[i]+f2[i-tar];
    65         }
    66         printf("%3d
    ",ans);
    67     }
    68     return 0;
    69 }

                                                      具体各个背包问题详解可以参考:低调小一

    -----------------------------------------------------------------------------------------------------------------------------------------------------------------

    活在现实,做在梦里。
  • 相关阅读:
    客户端IP获取
    文件下载公共方法 以及调用
    文件压缩和解压缩工具类
    下载
    URLencoder类防止下载后的文件名乱码
    SQL行转列
    处理千万级以上的数据提高查询速度的方法
    获取本月的第一天和最后一天
    【机器学习理论】概率论与数理统计--假设检验,卡方检验,t检验,F检验,方差分析
    【机器学习实践】Jupyter Notebook安装 侧边导航栏功能 操作及其他常用扩展功能介绍
  • 原文地址:https://www.cnblogs.com/do-it-best/p/5350677.html
Copyright © 2011-2022 走看看