1. 程式人生 > >HDU2602/HDU1114/HDU2191(重新整理一下01揹包,完全揹包,多重揹包)

HDU2602/HDU1114/HDU2191(重新整理一下01揹包,完全揹包,多重揹包)

好長時間不做揹包的問題,有一點遺忘,現在把這些問題整理一下~

一.01揹包(HDU2602)

題目:http://acm.hdu.edu.cn/showproblem.php?pid=2602

題意就是普通的01揹包,給出n種物品和揹包容量,給出每種物品的重量和價值,求當前揹包最多能達到的價值.(c[i]表示價值,w[i]表示重量)

在二維中,dp[i][j]表示把前i件物品放入容量為v的揹包中所能達到的最大價值,狀態轉移方程為:dp[i][j]={max(dp[i][j],dp[i-1][j-w[i]]+c[i])}.

在這裡用一維的方法來解決這個問題,dp[v]表示當前是容量為v的揹包能達到的最大價值,狀態轉移方程為:dp[v]=max{f[v],f[v-c[i]]+w[i]}.

程式碼:

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <stack>
#include <queue>
#include <vector>
#include <algorithm>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
int c[2000];//價值
int w[2000];//重量
int dp[2000];
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n,v;
        mem(dp,0);
        scanf("%d%d",&n,&v);
        for(int i=0; i<n; i++)scanf("%d",&c[i]);
        for(int i=0; i<n; i++)scanf("%d",&w[i]);//讀入資料
        for(int i=0; i<n; i++)//容量v在前i件物品時可以得到的最大值
            for(int j=v; j>=w[i]; j--)//注意這裡是逆序,可以避免重複放置
                dp[j]=max(dp[j],dp[j-w[i]]+c[i]);
        printf("%d\n",dp[v]);
    }
    return 0;
}
二.完全揹包(HDU1114)

題目:http://acm.hdu.edu.cn/showproblem.php?pid=1114

思路:題意是給出了小豬存錢罐的重量和存錢罐最多能承受的重量(算出它的承重),然後幾組資料,包括錢幣的價值與重量,求最多裝多少錢。這是一個完全揹包問題,錢幣有無限件可以用,按照上面的01揹包的思路,寫出狀態轉移方程:f[i][v]=max{f[i-1][v-k*c[i]]+k*w[i]|0<=k*c[i]<=v},用一維來表示:f[v]=max{f[v],f[v-c[i]]+w[i]},看上去和01揹包一樣,但是注意,這裡的迴圈要順序寫,因為每種揹包都是無限的。當我們把i從1到N迴圈時,f[v]表示容量為v在前i種揹包時所得的價值,這裡我們要新增的不是前一個揹包,而是當前揹包。所以我們要考慮的當然是當前狀態。引用揹包九講中的話“你會發現,這個虛擬碼與

P01的虛擬碼只有v的迴圈次序不同而已。 為什麼這樣一改就可行呢?首先想想為什麼P01中要按照v=V..0的逆序來迴圈。這是因為要保證第i次迴圈中的狀態f[i][v]是由狀態f[i-1] [v-c[i]]遞推而來。換句話說,這正是為了保證每件物品只選一次,保證在考慮“選入第i件物品”這件策略時,依據的是一個絕無已經選入第i件物品的 子結果f[i-1][v-c[i]]。而現在完全揹包的特點恰是每種物品可選無限件,所以在考慮“加選一件第i種物品”這種策略時,卻正需要一個可能已選入第i種物品的子結果f[i][v-c[i]],所以就可以並且必須採用v=0..V的順序迴圈。這就是這個簡單的程式為何成立的道理。”

程式碼:

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <stack>
#include <queue>
#include <vector>
#include <algorithm>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
int value[1000];
int weight[1000];
int dp[1000005];
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int v,wa,wb;
        scanf("%d%d",&wa,&wb);
        v=wb-wa;//減去本身的重量
        int n;
        scanf("%d",&n);
        for(int i=0; i<n; i++)
            scanf("%d%d",&value[i],&weight[i]);
        for(int i=0; i<=v; i++)
            dp[i]=10000000;//求最小的,所以初始化為最大值
        dp[0]=0;
        for(int i=0; i<n; i++)
            for(int j=weight[i]; j<=v; j++)
                dp[j]=min(dp[j],dp[j-weight[i]]+value[i]);
        if(dp[v]==10000000)
            printf("This is impossible.\n");
        else
            printf("The minimum amount of money in the piggy-bank is %d.\n",dp[v]);
    }
    return 0;
}
三、多重揹包(HDU2191)

題目:http://acm.hdu.edu.cn/showproblem.php?pid=2191

思路:多重揹包和以上兩種的不同點在於,多重揹包給了具體的重量,價錢,數量,可以轉換為01揹包求解(程式碼1),也可以進行二進位制優化,將第i種物品分成若干件物品,其中每件物品有一個係數,這件物品的費用和價值均是原來的費用和價值乘以這個係數。使這些係數分別為 1,2,4,...,2^(k-1),n[i]-2^k+1,且k是滿足n[i]-2^k+1>0的最大整數。例如,如果n[i]為13,就將這種 物品分成係數分別為1,2,4,6的四件物品,這種方法有模板(程式碼2),這樣就將第i種物品分成了O(log n[i])種物品,將原問題轉化為了複雜度為<math>O(V*Σlog n[i])的01揹包問題,是很大的改進,還有樓天城的單調佇列法,表示不會。。。

程式碼1:

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <stack>
#include <queue>
#include <vector>
#include <algorithm>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
int value[1000];//價值
int weight[1000];//重量
int num[1000];//數量
int dp[1000005];
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        mem(dp,0);
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=0; i<m; i++)
            scanf("%d%d%d",&value[i],&weight[i],&num[i]);
        for(int i=0; i<m; i++)
            for(int j=1; j<=num[i]; j++)//把數量展開
                for(int k=n; k>=value[i]; k--)
                    dp[k]=max(dp[k],dp[k-value[i]]+weight[i]);
        printf("%d\n",dp[n]);
    }
    return 0;
}
程式碼2:
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <stack>
#include <queue>
#include <vector>
#include <algorithm>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
int value[1000];//價值
int weight[1000];//重量
int num[1000];//數量
int dp[1000005];
int v,m;
void bag01(int c,int w)//01揹包
{
    int i;
    for(i=v; i>=c; i--)
    {
        if(dp[i]<dp[i-c]+w)
        {
            dp[i]=dp[i-c]+w;
        }
    }
}
void bagall(int c,int w)//完全揹包
{
    int i;
    for(i=c; i<=v; i++)
    {
        if(dp[i]<dp[i-c]+w)
        {
            dp[i]=dp[i-c]+w;
        }
    }
}
void multbag(int c,int w,int n)//多重揹包
{
    if(c*n>=v)
    {
        bagall(c,w);
        return ;
    }
    int k=1;
    while(k<=n)
    {
        bag01(k*c,k*w);
        n=n-k;
        k=k*2;
    }
    bag01(n*c,n*w);
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        mem(dp,0);
        scanf("%d%d",&v,&m);
        for(int i=0; i<m; i++)
            scanf("%d%d%d",&value[i],&weight[i],&num[i]);
        for(int i=0; i<m; i++)
            multbag(value[i],weight[i],num[i]);//套模板
        printf("%d\n",dp[v]);
    }
    return 0;
}
不太會寫這種總結性的,姑且看看。。。


相關推薦

HDU2602/HDU1114/HDU2191(重新整理一下01揹包完全揹包多重揹包)

好長時間不做揹包的問題,有一點遺忘,現在把這些問題整理一下~ 一.01揹包(HDU2602) 題目:http://acm.hdu.edu.cn/showproblem.php?pid=2602 題意就

HDU 2191 - 悼念512汶川大地震遇難同胞——珍惜現在感恩生活 (多重揹包

題目 急!災區的食物依然短缺! 為了挽救災區同胞的生命,心繫災區同胞的CK準備自己採購一些糧食支援災區,現在假設CK一共有資金n元,而市場有m種大米,每種大米都是袋裝產品,其價格不等,並且只能整袋購買。 請問:CK能用有限的資金最多能採購多少公斤糧食呢? Input 輸入資料首先

悼念512汶川大地震遇難同胞——珍惜現在感恩生活(多重揹包

Description 急!災區的食物依然短缺! 為了挽救災區同胞的生命,心繫災區同胞的你準備自己採購一些糧食支援災區,現在假設你一共有資金n元,而市場有m種大米,每種大米都是袋裝產品,其價格不等,並且只能整袋購買。 請問:你用有限的資金最多能採購多少公斤糧食呢? 後記: 人生是一個充滿了變

悼念512汶川大地震遇難同胞——珍惜現在感恩生活 (多重揹包

題目 急!災區的食物依然短缺! 為了挽救災區同胞的生命,心繫災區同胞的CK準備自己採購一些糧食支援災區,現在假設CK一共有資金n元,而市場有m種大米,每種大米都是袋裝產品,其價格不等,並且只能整袋購買。 請問:CK能用有限的資金最多能採購多少公斤糧食呢

動態規劃之背包問題-01背包+完全背包+多重背包

自己 動態規劃 問題 動態 重復 -- 今天 code i++ 01背包 有n種不同的物品,每種物品分別有各自的體積 v[i],價值 w[i] 現給一個容量為V的背包,問這個背包最多可裝下多少價值的物品。 1 for(int i = 1; i <= n; i++)

資料庫基礎(3)函式依賴-平凡依賴完全依賴部分依賴傳遞依賴

函式依賴是關係資料庫中非常重要的概念 包括平凡依賴,完全依賴,部分依賴以及傳遞依賴 ,這些都是關係資料庫正規化的基礎 函式依賴基本概念 函式依賴基本定義 簡單來說就是,只要屬性X的屬性值一樣(x1=x2) 那麼 屬性Y中的屬性值就一樣(y1=y2),就說明Y依賴於X

揹包問題小總結 習題(動態規劃01揹包(第k優解)完全揹包多重揹包)acm杭電HDU2639HDU2602HDU1114HDU2191

1、01揹包(每種物品只有一個) 題目 有N件物品和一個容量為V的揹包。第i件物品的費用是c[i],價值是w[i]。 求解將哪些物 品裝入揹包可使價值總和最大。 基本思路 這是最基礎的揹包問題,特點是:每種物品僅有一件,可以選擇放或不放。 用子問題定義狀態:    

演算法模板(一) 01揹包多重揹包完全揹包

01揹包 #include<bits/stdc++.h> using namespace std; int dp[300][3000]; int w[3000],v[3000]; int N,V; int main(){ cin>>N>>V; for(re

揹包問題-01揹包完全揹包多重揹包

揹包問題-01揹包,完全揹包,多重揹包 01揹包: 概念: 有Goods_Num件物品,MAX_Volume的最大裝載量,每種物品只有一件,每種物品都有對應的重量或者說體積Volume[i],價值Value[i],求解裝包的最大價值 狀態轉移方程推

回溯法總結+四個小例題(裝載問題01揹包n後最大團m著色)

目錄   回溯法的基本策略  回溯法的基本策略 回溯法的解空間 回溯法基本思想 回溯法解題步驟 遞歸回溯和迭代回溯 子集樹和排列樹 裝載問題 01揹包問題回溯法求解 n後問題 圖的最大團問題 圖的m著色

【POJ1014】Dividing 多重揹包二進位制物品拆分轉01揹包

直接做01揹包,即把物品數量累加,做20000物品的01揹包指定TLE,不用我說了吧! 本文的優化是二進位制優化,O(logn),至於完全揹包記錄已使用個數的O(n)演算法本文不進行講解,在部落格的“

史上最易懂的01揹包完全揹包多重揹包講解

                                        揹包之01揹包、完全揹包、多重揹包詳解 PS:大家覺得寫得還過得去,就幫我把部落格頂一下,謝謝。 首先說下動態規劃,動態規劃這東西就和遞迴一樣,只能找區域性關係,若想全部列出來,是很難的,比

揹包模板(01完全多重揹包的二進位制優化和單調佇列優化

揹包問題 1,01揹包 揹包問題的基礎,總體積為V的揹包,有n件體積v【i】,價值w【i】的物品,求能裝物品的最大總價值 void zero(int v,int w) { for(int j=V;j>=v;j--) { dp[j]=max(dp[j],dp[j

21869 Problem C 貨幣系統 (順便進行01揹包的總結歸納內含自己想的有趣例子幫助理解。。)

問題 C: 貨幣系統 時間限制: 1 Sec  記憶體限制: 128 MB 提交: 94  解決: 32   題目描述 母牛們不但建立了他們自己的政府而且選擇了建立了自己的貨幣系統。 [In t

01揹包的四種解法詳解:動態規劃貪心法回溯法優先佇列式分支限界法(C語言編寫)

最近剛完成了演算法課程設計,題目是用多種解法解決01揹包問題,經過一番探索,終於成功的用四種方法完成了本次實驗,下面記錄分享一下成果: 首先解釋下什麼是01揹包問題:給定一組共n個物品,每種物品都有自己的重量wi, i=1~n和價值vi, i=1~n,在限定的總重量(揹包的

01揹包完全揹包多重揹包

01揹包 #include <stdio.h> int c[101][1001]={0};//定義100個物品1000重量的總價值陣列 void calcMaxValues(int n,

01揹包完全揹包C++實現

首先,上自己的程式碼,由於程式碼註釋詳細,我就不解釋啦。看程式碼就好O(∩_∩)O。 程式碼轉換為了01揹包問題求解。 不瞭解01揹包演算法的同學也可以到上述網址先學習。 本程式碼可以輸出價值與揹包中的物品。 供大家一起學習使用,如需轉載程式碼請告知本人。 先為

詳解 01完全多重揹包

揹包問題泛指以下這一種問題: 給定一組有固定價值和固定重量的物品,以及一個已知最大承重量的揹包,求在不超過揹包最大承重量的前提下,能放進揹包裡面的物品的最大總價值。 這一類問題是典型的使用動態規劃解決的問題,我們可以把揹包問題分成3種不同的子問題:0-1揹包問題、完全揹包和多重揹包問題。下面對這三種問題分別進

分支限界法總結--例題(01揹包最大團單源最短路徑裝載問題佈線問題)

目錄 分支限界法剪枝搜尋策略(廣度搜索)與演算法框架 01揹包問題 最大團 單源最短路徑 裝載問題 佈線問題 分支限界法剪枝搜尋策略(廣度搜索)與演算法框架 基本思想 分支限界法與回溯法求解目標不同,回溯法的求解目標是找出