基礎動態規劃-完全揹包問題+POJ1742(遞推式優化)

完全揹包問題

一共有n種價值和重量爲viwiv_i,w_i的物品,如果我們的揹包最大能放V的重量,那麼如何才能取價值最大呢?
這種問題規模,可以用兩種維度的變量控制,

比如
種類和體積
前i種體積爲v的最大重量dp[i][v]

另一種思路
種類和質量
前i種,質量爲w,最少體積dp[i][w]

討論第一種控制方法

顯然dp[i][v]=maxk(dp[i][vkvi])+kwidp[i][v]=max_k(dp[i][v-k*v_i])+k*w_i
就是說我們可以將前i種不超過體積v最大質量問題,以用第i種物品k次,完全劃分。
這種思路雖然可以解決問題,但是顯然有三重循環,時間複雜度過高。

優化

可以參考之前的寫的計數問題,有詳細解釋,以至少用1次和一次都不用做劃分。
dp[i][v]=max(dp[i1][v],dp[i][vvi]+wi)dp[i][v]=max(dp[i-1][v],dp[i][v-vi]+w_i)
這樣就是兩重循環解決。

POJ1742

Description

People in Silverland use coins.They have coins of value A1,A2,A3…An Silverland dollar.One day Tony opened his money-box and found there were some coins.He decided to buy a very nice watch in a nearby shop. He wanted to pay the exact price(without change) and he known the price would not more than m.But he didn’t know the exact price of the watch.
You are to write a program which reads n,m,A1,A2,A3…An and C1,C2,C3…Cn corresponding to the number of Tony’s coins of value A1,A2,A3…An then calculate how many prices(form 1 to m) Tony can pay use these coins.
Input

The input contains several test cases. The first line of each test case contains two integers n(1<=n<=100),m(m<=100000).The second line contains 2n integers, denoting A1,A2,A3…An,C1,C2,C3…Cn (1<=Ai<=100000,1<=Ci<=1000). The last test case is followed by two zeros.
Output

For each test case output the answer on a single line.

分析

這個問題和完全揹包類似,但是有些不一樣的地方是,每種物品有數量限制。
如用直接的思路,會因爲有第三重循環就會超時,我們必須得優化遞推關係式。

優化思路

如何優化呢?
一種思路是重新定義dp數組。
在這我們定義dp[i][w]dp[i][w]是湊成w時剩餘i中物品的數量。
這種思路怎麼來的,這是一種常見的思路,用dp數據存儲更多有效信息,比如剩餘的數量。

如果一個都不需要用就湊成了,
dp[i][w]=dp[i1][w]dp[i][w]=dp[i-1][w]
如果w-wi<0,無法湊出,定義爲-1
dp[i][w]=1dp[i][w]=-1
否則
dp[i][w]=dp[i][wwi]1dp[i][w]=dp[i][w-wi]-1,因爲要用一個所以減少一個。

代碼

下方代碼對存儲做了些優化常見的只用一維dp節省空間。

#include<iostream>
#include<algorithm>
#include<map>
#include<vector>
#include<queue>
using namespace std;
int dp[100000+1];
int main(){
    int n,m;
    while(true){
        cin>>n>>m;
        if(n==0 && m==0) break;
        
        vector<int> value;
        vector<int> count;
        int tmp;
        for(int i=0;i<n;i++)
        {
            cin>>tmp;
            value.push_back(tmp);
        }
        
        for(int i=0;i<n;i++)
        {
            cin>>tmp;
            count.push_back(tmp);
        }
        for(int i=0;i<n;i++){
            for(int j=0;j<=m;i++){
                if(dp[j]>=0){
                    dp[j]=count[i];
                }else if(j<value[i]|| dp[j - value[i]] <= 0){
                    dp[j]=-1;
                }else{
                    dp[j]=dp[j-value[i]]-1;
                }
            }
        }
    }
    //bind2nd綁定第二個參數到greater_equal中去
     auto ans=count_if(dp+1, dp+1+m, bind2nd(greater_equal<int>(), 0));
    cout << ans << endl;
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章