zoukankan      html  css  js  c++  java
  • 甜点 【多重背包】

    【问题描述】
    小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 }
  • 相关阅读:
    dotnet 控制台读写 Sqlite 提示 no such table 找不到文件
    dotnet 控制台读写 Sqlite 提示 no such table 找不到文件
    dotnet 控制台 Hangfire 后台定时任务
    dotnet 控制台 Hangfire 后台定时任务
    dotnet 获取指定进程的输入命令行
    dotnet 获取指定进程的输入命令行
    PHP sqrt() 函数
    PHP sinh() 函数
    PHP sin() 函数
    PHP round() 函数
  • 原文地址:https://www.cnblogs.com/Syameimaru/p/9293381.html
Copyright © 2011-2022 走看看