【二维费用的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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值