1. 程式人生 > >【二維費用的01揹包 HDU3496 HDU2184】

【二維費用的01揹包 HDU3496 HDU2184】

HDU3496    
已空間優化
    疑惑點在 dp[時間][看電影數量]的初始化問題上面

    dp[0][0]=0。。。。是吧
    dp[0][i]=-inf,,,,,,,這個-inf一定要足夠大,題目中的資料是輸出的最大價值是<2^31 LL 在dp[0][i]更新的時候,最後是dp[0][i]+總和val,那這兒的-inf肯定是要足夠足夠大 最後才保證dp[0][i]在更新的時候,選取最大值時才取不到這個不合理的值

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <cstring>
#define X 1005
using namespace std;
 int dp[X][X];
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int N,M,L;
        int w[X],v[X];//L分鐘看動畫片

        scanf("%d%d%d",&N,&M,&L);
        for(int i=0;i<N;++i)
        {
            scanf("%d%d",&w[i],&v[i]);
        }
        for(int i=0;i<=L;++i)
            for(int j=0;j<=M;++j)
        {
            if(j==0)
                dp[i][j]=0;
            else
                dp[i][j]=-1000;
        }
       for(int i=0;i<N;++i)
       {
           for(int j=L;j>=w[i];--j)
           {
               for(int k=M;k>=1;--k)
               {
                  dp[j][k]=max(dp[j][k],dp[j-w[i]][k-1]+v[i]);
               }
           }
       }
       if(dp[L][M]<0)
        dp[L][M]=0;//
       cout<<dp[L][M]<<endl;
    }
    return 0;
}

HDU2184
看出來是一道二維01揹包問題
可是怎麼確定揹包的容量是多少呢?

wa證明我的二維01揹包思路是錯誤姿勢
自己寫不出來二維01揹包實現的,看了網上的題解都是對滾動陣列進行分析加上對揹包容量的固定偏移量來實現好菜,
滾動陣列的正序及逆序:
深入一下滾動陣列吧,可以把樣例中的負值全部都轉化為正直,然後用畫表格的方式走一遍滾動陣列在實現的時候是怎麼樣把當前第i件物品更新到dp裡面的
(手動實現)這時候每個揹包的容量下對應的物品都是放入一次的(空間優化的逆序放入過程),可是存在負值的時候就對應的不同種容量的揹包狀態是對應得一件物品得多件(自然就不是01揹包了)
然後就有了題解中大神理解得對佔用負的容量的 一個正序更新dp陣列過程(也是自己手動模擬過程,我模擬了一遍)

沒有給出揹包容量轉化為用一定的偏移量來代替沒有給出的容量:
因為資料最小負值為-1e5 最大值1e5,那麼dp更新範圍在2e5之間,所以可以用2e5代表最大的容量,容量最小的基數為1e5,避免出現-1e5的資料使陣列訪問越界

(原先寫得初始化思路:題目使容量儘量大,所以初始化為-inf d[1e5]就代表了01原型揹包中的dp[0],((感覺是錯誤得因為,這道題本身就是含有負值,搞為0得話,就會導致含有一個負值很大得時候他永遠不會被選中
((感覺是這樣(⊙﹏⊙)
再有的細節就是對於兩個資料都是<0肯定不會選中,所以可以直接跳過。
參考

#include <bits/stdc++.h>
#include <iostream>
#define X 10005
#define inf 0x3f3f3f3f
#define PI 3.141592653589793238462643383
#define IO  ios::sync_with_stdio(false),cin.tie(0), cout.tie(0);
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
typedef long long ll;
const ll moad=1e9+7;
const int maxn=1e6+10;
int dp[maxn];
int w[maxn];
int c[maxn];
int vis[maxn];
int Max=2e5;//固定偏移量
int main()
{
    int n;
    while(cin>>n)
    {
        for(int i=0;i<n;++i){cin>>c[i]>>w[i];if(c[i]<=0&&w[i]<=0)--i,n--;}
        for(int i=0;i<=Max;++i) dp[i]=-inf;
        dp[100000]=0;
       for(int i=0;i<n;++i)
       {
           if(c[i]>=0)
           {
               for(int j=Max;j>=c[i];--j)
                    if(dp[j-c[i]]>-inf)
                dp[j]=max(dp[j],dp[j-c[i]]+w[i]);
           }
           if(c[i]<0)
           {
               for(int j=0;j<=Max+c[i];++j)
                if(dp[j-c[i]]>-inf)
                dp[j]=max(dp[j],dp[j-c[i]]+w[i]);
           }
       }
       int ans=0;
       for(int i=1e5;i<=Max;++i)
        if(dp[i]>0&&(dp[i]+i-Max/2)>ans)
            ans=dp[i]+i-1e5;
       cout<<ans<<endl;
    }
    return 0;
}