Big Event in HDU(HDU-1171)

本文深入探讨了背包问题的多种解法,包括01背包、多重背包及其优化策略,如单调队列和二进制优化。通过详细的时间复杂度分析和代码实现,帮助读者理解并掌握背包问题的高效解决方案。


1 题意

  有 n n n种物品,每种物品的价值分别分 v a l 1 , v a l 1 , v a l 2 , . . . , v a l n val_{1},val_{1},val_{2},...,val_{n} val1,val1,val2,...,valn,数量分别为 n u m 1 , n u m 2 , . . . , n u m n ( 1 ⩽ n ⩽ 50 , 1 ⩽ v a l ⩽ 50 , 1 ⩽ n u m ⩽ 100 ) num_{1},num_{2},...,num_{n}(1 \leqslant n \leqslant 50,1 \leqslant val \leqslant 50,1 \leqslant num \leqslant 100) num1,num2,...,numn(1n50,1val50,1num100)。要求按价值尽量均分物品。
  链接:link


2 思路

  求出所有物品的总价值,再用总价值的一半作为背包容量,看是否能装满。

2.1 01背包

  将所有的物品拆分成单个,用01背包解题。

2.1.1 时间复杂度分析

  一共可拆分出 n × n u m n \times num n×num个物品,背包容量为 n × n u m × v a l 2 \frac{n \times num \times val}{2} 2n×num×val,时间复杂度为 O ( n 2 × n u m 2 × v a l 2 ) \mathcal{O}(\frac{n^{2} \times num^{2} \times val}{2}) O(2n2×num2×val)

2.1.2 实现

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=50+10;
const int V=50+10;
const int M=100+10;
int val[N*M+10],dp[N*V*M/2],n;
int main(){
   
   
    while(~scanf("%d",&n)&&n>=0){
   
   
        int sum=0,cnt=0;
        for(int i=1;i<=n;i++){
   
   
            int tval,tnum;scanf("%d %d",&tval,&tnum);
            sum+=tval*tnum;
            while(tnum--) val[++cnt]=tval;
        }
        int hsum=sum>>1;
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=cnt;i++){
   
   
            for(int j=hsum;j>=val[i];j--){
   
   
                dp[j]=max(dp[j],dp[j-val[i]]+val[i]);
            }
        }
        printf("%d %d\n",sum-dp[hsum],dp[hsum]);
    }
    return 0;
}

2.2 多重背包

2.2.1 朴素实现

  由于每种物品都可以选 [ 0 , n i ] [0,n_{i}] [0,ni]个,所以需要多一层循环枚举数量。

2.2.1.1 时间复杂度分析

  一共 n n n个物品,背包容量为 n × n u m × v a l 2 \frac{n \times num \times val}{2} 2n×num×val,每个物品需要枚举 n u m num num个数量,所以时间复杂度为 O ( n 2 × n u m 2 × v a l 2 ) \mathcal{O}(\frac{n^{2} \times num^{2} \times val}{2}) O(2n2×num

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值