【背包问题】从小数据到大数据

版权声明:转载标注来源喔~ https://blog.csdn.net/iroy33/article/details/89682830

1、普通01背包

for i=1:n
    for j=0:W

if(j<w[i])
    dp[i][j]=dp[i-1][j];
else
    dp[i][j]=max(dp[i][j],dp[i][j-w[i]]+w[i];

2、01背包问题之2

题目特征:背包重量太大,开不了那么大的数组。普通01背包中的时间复杂度O(nW),现在就不够用了。

解决方案:价值的范围较小,试着改变dp的方向。之前的方法中,针对不同的重量限制计算最大的价值,现在针对不同的价值计算最小的重量。

状态定义:dp[i][j] 前i个物品中挑选出价值总和为j时总重量的最小值(不存在时是一个充分大的INF),初始值dp[0][0]=0,dp[0][j]=INF。

状态转移:dp[i][j]=min(dp[i][j],dp[i][j-v[i]]+w[i])

最终答案:dp[n][j]\leqslant W 的最大j的最大j(时间复杂度O(n\sum v_i)

hdu 6495冰水挑战

思路:背包载荷是c,每个物品的重量是ai,每个物品的价值是1。一般来说,会想到针对不同的体力计算最大的挑战个数,也就是dp[i][j]代表考虑j点体力最多能挑战多少个,这样的话j的数据量到达1e9,时空复杂度都hold不住,相对的针对挑战个数考虑体力的最小值的话(针对价值考虑重量),挑战个数的最大值是n,1e3,时间复杂度就是1e3*1e3

针对挑战个数考虑体力的最小值的话----->为了方便处理本题,改成求剩余体力的最大值,dp[n][i]>0的最大的i就是答案

注意不管咋样,他都是个01背包,按照不选和选两种情况分类讨论即可

不选它:参考普通01背包,dp[i][j]=dp[i-1][j],  dp[i][j]=dp[i-1][j]+c[i] 本题额外判断它是否能从dp[i-1][j]转移过来,即dp[i-1][j]>0

选它:参考01背包,dp[i][j=max(dp[i][j],dp[i][j-w[i]]+v[i]), dp[i][j]=max(dp[i][j],挑战它之前的体力-a[i]+c[i]),注意由于选它dp[i][j]一定是由dp[i-1][j-1]转移过来的,所以挑战它之前的体力=min(dp[i-1][j-1],b[i]),要判断是否能成功转移

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long LL;
const int N=1e3+10;
LL a[N],b[N],c[N];
LL dp[N][N];           //最多能完成n个挑战   总价值最大是n4
//减少的体力最小-->剩下的体力最大
//写二维的时候感觉还是正着写比较酥服

int n;
LL C;
const int INF=1e9;
int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        cin>>n>>C;
        for(int i=1;i<=n;++i)
            cin>>a[i]>>b[i]>>c[i];
        memset(dp,-INF,sizeof(dp));
        dp[0][0]=C;
        for(int i=1;i<=n;++i)       //要得到体力消耗的最小值
        {
            for(int j=0;j<=n;++j)
            {
        
                if(dp[i-1][j]>0)
                    dp[i][j]=max(dp[i][j],dp[i-1][j]+c[i]);
                if(j)
                {
                    int tmp=min(dp[i-1][j-1],b[i]);
                    if(tmp>a[i])                //考虑选它
                    {
                        dp[i][j]=max(dp[i][j],tmp-a[i]+c[i]); //c[i]写外面了可真是该死
                    }
                }

            }

        }

        int ans;
        for(int i=n;i>=0;--i)
        {
            if(dp[n][i]>0)
            {
                ans=i;
                break;
            }
        }
        cout<<ans<<endl;
    }

}

3、超大背包问题

nyoj 1091

https://blog.csdn.net/zhou_yujia/article/details/52596058

https://blog.csdn.net/M_GSir/article/details/52564564

https://blog.csdn.net/mengxiang000000/article/details/53114701 折半枚举 codeforces

https://blog.csdn.net/qq_24489717/article/details/49950027 DFS和折半枚举两种方案

猜你喜欢

转载自blog.csdn.net/iroy33/article/details/89682830