甜点 【多重背包】
【问题描述】
小z准备举办一个比赛。他需要提供一些甜点给参赛者来补充能量。每种甜品有一定的能量ti和大小ui,且每种甜点最多有vi个。
小z准备用箱子来包装甜点。箱子可以容纳一定体积的甜点且需要一定的费用。小z有一种魔法,可以将一个甜点分成多份装在箱子里,最后再合在一起(但合成之后必须是完整的一个)。
小z想知道准备能量至少为P的甜点的最小大小和最少需要多少费用来购买箱子,如果最少费用超过小z所拥有的钱数k则输出FAIL。
【输入格式】
第一行为4个正整数n,m,p, k( 1 ≤ n ≤ 200,1 ≤ m ≤ 200,0 ≤ p ≤ 50000, k <= 50000)分别代表甜点种类,箱子种类和参赛者比赛所需要补充的能量和小z所拥有的钱数。
接下来的n行,每行包含3个整数ti, ui, vi ( 1 ≤ ti ≤ 100,1 ≤ ui ≤ 100,1 ≤ vi ≤ 100) , 代表第i类甜点可以提供ti的能量,它的大小为ui并且小明最多有vi个该种类的甜点。
接下来又有m行,每一行包含3个整数xi, yi, zi ( 1 ≤ xj ≤ 100,1 ≤ yj ≤ 100,1 ≤ zj ≤ 100), 代表第i类箱子可以容纳xi大小的甜点,该类箱子的单价yi,并且小z最多可以使用zi个该类的箱子。
【输出格式】
第一行请输出最小的甜点大小。
第二行请输出最小的箱子费用,并且费用不能超过k。否则,输出FAIL。
【样例输入】
5 3 34 34
1 4 1
9 4 2
5 3 3
1 3 3
5 3 2
3 4 5
6 7 5
5 3 8
【样例输出】
19
12
【数据范围与约定】
30%: n, m <= 15, p, k <= 1000
60%: n, m <= 50, p, k <= 5000
100%: n, m <= 200, p <= 50000, k <= 50000
[测试数据](https://files.cnblogs.com/files/Syameimaru/z.zip)
---------------------------------------------------------------------------------------------------------------------------------
题解:
首先,我们可以以每个甜点的能量为价值,体积为费用,建立一个多重背包问题。
由于数据有点大,我们可以选择二进制优化或者单调队列优化。
然后,我们从体积从小到大遍历一边,直到找到了一个能量大于需求,记录下来这个体积。
然后我们以箱子的体积为价值,费用为费用,跑一边多重背包。
费用从小到k遍历一边,找到第一个价值大于体积的费用,记录下来这个费用。如果最终没有找到,那么输出FAIL。
代码如下
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 const int maxn = 300; 5 int n,m,p,k,T[maxn],U[maxn],V[maxn],X[maxn],Y[maxn],Z[maxn]; 6 struct Node { 7 int size,v; 8 }P[30000]; 9 int A[100002],B[100002],tot=0; 10 inline void devide(int x) { 11 int l = 1; 12 while(l<=V[x]) { 13 P[++tot].size=U[x]*l; 14 P[tot].v=T[x]*l; 15 V[x]-=l; 16 l<<=1; 17 } 18 if(V[x]) { 19 P[++tot].size=U[x]*V[x]; 20 P[tot].v=T[x]*V[x]; 21 } 22 return; 23 } 24 inline void devide2(int x) { 25 int l =1; 26 while(l<=Z[x]) { 27 P[++tot].size=Y[x]*l; 28 P[tot].v=X[x]*l; 29 Z[x]-=l; 30 l<<=1; 31 } 32 if(Z[x]) { 33 P[++tot].size=Y[x]*Z[x]; 34 P[tot].v=X[x]*Z[x]; 35 } 36 return; 37 } 38 int main() { 39 freopen("z.in","r",stdin); 40 freopen("z.out","w",stdout); 41 scanf("%d%d%d%d",&n,&m,&p,&k); 42 for(register int i=1;i<=n;i++) 43 scanf("%d%d%d",&T[i],&U[i],&V[i]); 44 for(register int i=1;i<=m;i++)scanf("%d%d%d",&X[i],&Y[i],&Z[i]); 45 for(register int i=1;i<=n;i++) devide(i); 46 for(register int i=1;i<=tot;i++) { 47 for(register int V = 100000;V>=P[i].size;V--) { 48 A[V]=std::max(A[V],A[V-P[i].size]+P[i].v); 49 } 50 } 51 int ans1; 52 for(register int i=1;i<=100000;i++) { 53 if(A[i]>=p) { 54 ans1=i; 55 printf("%d\n",i); 56 break; 57 } 58 } 59 tot=0; 60 for(register int i=1;i<=m;i++) devide2(i); 61 for(register int i=1;i<=tot;i++) { 62 for(register int V = 100000;V>=P[i].size;V--) { 63 B[V]=std::max(B[V],B[V-P[i].size]+P[i].v); 64 } 65 } 66 for(register int i=1;i<=k;i++) { 67 if(B[i]>=ans1) { 68 printf("%d\n",i); 69 return 0; 70 } 71 } 72 puts("FAIL"); 73 return 0; 74 }