• 甜点 【多重背包】


    【问题描述】
    小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
    ",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
    ",i);
    69             return 0;
    70         }
    71     }
    72     puts("FAIL");
    73     return 0;
    74 }
  • 相关阅读:
    PHP 获取js中变量的方法
    Golang文件操作整理
    Golang的文件处理方式-常见的读写
    golang中文件以及文件夹路径相关操作
    服务器常用的状态码及其对应的含义
    left join on 和where条件的放置
    golang 文件导入数据追加sheet
    使用io/ioutil进行读写文件
    Go语言编程中字符串切割方法小结
    Golang学习
  • 原文地址:https://www.cnblogs.com/Syameimaru/p/9293381.html
Copyright © 2020-2023  润新知