zoukankan      html  css  js  c++  java
  • POJ 1384 Piggy-Bank 完全背包分析

    给定储蓄罐空的和满的重量,有n种硬币,硬币有价值和重量,给出各种硬币的价值p[i]和对应的重量w[i],求储蓄罐里面硬币的最小价值,如果没有符合要求的放硬币的方式,输出 “this is impossible”。

    思路:

    相当于完全背包求最小值,n中硬币对应n个物体,物体可以取无限次,存储罐里硬币重量(满罐减空罐)相当于背包的体积V。

    法一:

    直接扩展01背包的方程,用dp[i,v]表示取前i种硬币,存储罐重量最大为v时的最小价值。状态转移方程为:dp[i,v]=min(dp[i-1,v-k*w[i]] + k*p[i]),0<=k<= V/w[i],取第i中硬币取k个。

    递推要求N*V个状态,求每一个状态需要时间为O(v/Weight[i]),总的时间复杂度为O(NV*Σ(V/c[i])),空间复杂度O(n2)

    递推式:

    for(int i=1; i<=n; ++i)    
      for(int v=w; v<=V; ++v)   
         for(int k=0; k*v<=V; ++k)     
         dp[i][v] = min(dp[i-1][v],dp[i-1][v-k*w]+p*k);
     

    法二:

    1、递推代码:(对经典代码的解释)

    for(int i=0; i<n; ++i)    
    for(int j=w; j<=V; ++j)     
            dp[j] = min(dp[j],dp[j-w]+p);

    2、空间优化:

    只用dp[v]即可,状态转移为:dp[v]=min(dp[v-k*w[i]] + k*p[i]),第i遍循环时,dp[i][v]只依赖于dp[i-1][v]的状态,前面的dp[0…i-1,v]都没用了,最后输出u的也是在dp[][v]里找结果,所以不用保存这些状态。这样需要保存两个dp[0][v]、dp[1][v]替换这两个变量就可以。

    进一步想,k=0时,相当于dp[i][v]=dp[i-1][v],接着枚举k都是和dp[i][v]比较的,也就是说,第i-1层循环算完后的结果相当于第i层的第一个状态,所以只需维护一个数组dp[v]就够了。

    3、时间优化:

    用第i个物品,即第i层循环,用dp[v-w]来更新dp[v]时,dp[v-w]已经更新过了,因为循环按照v = w to V来更新的,如下:

    dp[v] = min(dp[v]未更新, dp[v-w]已更新)+p)                               // 更新dp[v]

    = min ( dp[v]未更新, min(dp[v-w]未更新, dp[v-2w]已更新+p)+p)                 // 更新dp[v-w]

    = min ( dp[v]未更新, dp[v-w]未更新+p, min(dp[v-2w]未更新, dp[v-3w]已更新+p)+2p)  // 更新dp[v-2w]

    = min ( dp[v]未更新, dp[v-w]未更新+p, dp[v-2w]未更新+2p, … , dp[v-kw]未更新+kp)   // 更新dp[v-3w]

    = min (dp[v-k*w]未更新+k*p) (0<=k<=V/vi)

    算法复杂度:

    时间复杂度O(nV),空间复杂度O(n)

    算法步骤

    步骤1:读入数据,初始化dp[i]为无穷大,dp[0]=0

    步骤2:递推,递推公式如上,答案就是dp[V]

    代码:

    #include <cstdio> 
    #define min(a,b) (a<b)?a:b
    const int inf = 1e9,maxn = 8000; 
    int dp[maxn];
    int main()
    {
        int kase,V1,V ,n;
        int p, w; // value,weight
        scanf("%d",&kase);
        while(kase--){
            scanf("%d %d %d",&V1,&V,&n);
            V -= V1;
            // init 
            for(int i=1;i<=V; ++i) dp[i]=inf;       
            dp[0]=0;
            // DP
            for(int i=1; i<=n; ++i){    
                scanf("%d %d",&p,&w);
                for(int j=w; j<=V; ++j){     
                    dp[j] = min(dp[j],dp[j-w]+p);
                }
            }
            // output
            if(dp[V]==inf) printf("This is impossible.
    "); 
            else printf("The minimum amount of money in the piggy-bank is %d.
    ",dp[V]);       
        }    
        return 0;
    }
     
  • 相关阅读:
    Can't connect to local MySQL server through socket '/tmp/mysql.sock'
    reversePairs
    sort
    分割数组的最小值
    decode string
    276. 栅栏涂色
    133. Clone Graph
    Palindromic string
    爬楼梯
    正则匹配
  • 原文地址:https://www.cnblogs.com/tinyork/p/5044049.html
Copyright © 2011-2022 走看看