目录
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(1⩽n⩽50,1⩽val⩽50,1⩽num⩽100)。要求按价值尽量均分物品。
链接: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

本文深入探讨了背包问题的多种解法,包括01背包、多重背包及其优化策略,如单调队列和二进制优化。通过详细的时间复杂度分析和代码实现,帮助读者理解并掌握背包问题的高效解决方案。
&spm=1001.2101.3001.5002&articleId=107569668&d=1&t=3&u=8cb8adf1cb2a4c1faebdcc2f2c7ac635)
2万+

被折叠的 条评论
为什么被折叠?



