zoukankan      html  css  js  c++  java
  • 洛谷 P1064 金明的预算方案(01背包问题)

    传送门:Problem 1064

     https://www.cnblogs.com/violet-acmer/p/9852294.html

    题解:

      这道题是 “01”背包问题的变形。

      如果不考虑买附件必须买相应的主件这一条件下,这就是单纯的 “01”背包问题。

      那,这道题该如何做呢?

      注意看一下题干,每个主件最多有 2 个附件,那这就容易些了,枚举所有的可能;

      对于第 i 个主件,有以下五种可能:

      (1):不选主件 i 

      (2):只选主件 i

      (3):选主件 i + 附件1

      (4):选主件 i + 附件2

      (5):选主件 i + 附件1 + 附件2

      从这五个中找到最大的价值组合,并和 dp[i-1][ j ]判断,取最大值,当然在选择附件时,需要满足当前价值可以容下所选择的总价值。

    AC代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 using namespace std;
     4 #define P pair<int ,int >
     5 const int maxn=3.2e4+50;
     6 
     7 int n,m;
     8 int dp[70][maxn];
     9 P mainG[maxn];//存储主件信息
    10 P touchG[70][maxn];//touchG[i] : 存储主件 i 含有的附件信息
    11 int total[70];//total[i] : 主件 i 含有的附件个数
    12 int Val(P p){
    13     return p.first*p.second;
    14 }
    15 void Solve()
    16 {
    17     for(int i=1;i <= m;++i)
    18     {
    19         P one=touchG[i][1];
    20         P two=touchG[i][2];
    21         for(int j=1;j <= n;++j)
    22         {
    23             dp[i][j]=dp[i-1][j];
    24             if(j >= mainG[i].first)
    25                 dp[i][j]=max(dp[i][j],dp[i-1][j-mainG[i].first]+Val(mainG[i]));
    26             if(j >= mainG[i].first+one.first)
    27                 dp[i][j]=max(dp[i][j],dp[i-1][j-mainG[i].first-one.first]+Val(mainG[i])+Val(one));
    28             if(j >= mainG[i].first+two.first)
    29                 dp[i][j]=max(dp[i][j],dp[i-1][j-mainG[i].first-two.first]+Val(mainG[i])+Val(two));
    30             if(j >= mainG[i].first+one.first+two.first)
    31                 dp[i][j]=max(dp[i][j],dp[i-1][j-mainG[i].first-one.first-two.first]+Val(mainG[i])+Val(one)+Val(two));
    32         }
    33     }
    34     printf("%d
    ",dp[m][n]);
    35 }
    36 int main()
    37 {
    38     scanf("%d%d",&n,&m);
    39     for(int i=1;i <= m;++i)
    40     {
    41         int v,p,q;
    42         scanf("%d%d%d",&v,&p,&q);
    43         if(!q)
    44             mainG[i]=P(v,p);
    45         else
    46             touchG[q][++total[q]]=P(v,p);
    47     }
    48     Solve();
    49 }
    二维dp
     1 #include<iostream>
     2 #include<cstdio>
     3 using namespace std;
     4 #define P pair<int ,int >
     5 const int maxn=3.2e4+50;
     6 
     7 int n,m;
     8 int dp[maxn];
     9 P mainG[maxn];//存储主件信息
    10 P touchG[70][maxn];//touchG[i] : 存储主件 i 含有的附件信息
    11 int total[70];//total[i] : 主件 i 含有的附件个数
    12 int Val(P p){
    13     return p.first*p.second;
    14 }
    15 void Solve()
    16 {
    17     for(int i=1;i <= m;++i)
    18     {
    19         P one=touchG[i][1];
    20         P two=touchG[i][2];
    21         for(int j=n;mainG[i].first != 0 && j >= 1;--j)
    22         {
    23             if(j >= mainG[i].first)
    24                 dp[j]=max(dp[j],dp[j-mainG[i].first]+Val(mainG[i]));
    25             if(j >= mainG[i].first+one.first)
    26                 dp[j]=max(dp[j],dp[j-mainG[i].first-one.first]+Val(mainG[i])+Val(one));
    27             if(j >= mainG[i].first+two.first)
    28                 dp[j]=max(dp[j],dp[j-mainG[i].first-two.first]+Val(mainG[i])+Val(two));
    29             if(j >= mainG[i].first+one.first+two.first)
    30                 dp[j]=max(dp[j],dp[j-mainG[i].first-one.first-two.first]+Val(mainG[i])+Val(one)+Val(two));
    31         }
    32     }
    33     printf("%d
    ",dp[n]);
    34 }
    35 int main()
    36 {
    37     scanf("%d%d",&n,&m);
    38     for(int i=1;i <= m;++i)
    39     {
    40         int v,p,q;
    41         scanf("%d%d%d",&v,&p,&q);
    42         if(!q)
    43             mainG[i]=P(v,p);
    44         else
    45             touchG[q][++total[q]]=P(v,p);
    46     }
    47     Solve();
    48 }
    一维dp

       关于主件编号问题(踩坑了):

          m个物品,编号为 1~m,而不是按照主件的个数进行编号。

          例如:                

                  (正确编号)(错误编号)

            2000 10      

            500 1 0    1    1
            400 4 0    2    2
            300 5 1    3
            400 5 1    4
            200 5 0    5    3
            500 4 5    6
            400 4 0    7    4
            320 2 0    8    5
            410 3 0    9    6
            400 3 5    10

          找这个BUG找了好几个小时,mmp,心累啊.................

          

     

        

  • 相关阅读:
    java并发计算的几种基本使用示例
    axios、ajax和xhr前端发送测试
    Spring注解
    Android菜鸟教程笔记
    普通二叉树操作
    MyBatis
    mysql的select语句总结与索引使用
    sys.argv的意义[转]
    硬件小白学习之路(1)稳压芯片LM431
    FPGA小白学习之路(6)串口波特率问题的处理
  • 原文地址:https://www.cnblogs.com/violet-acmer/p/9845443.html
Copyright © 2011-2022 走看看