C++ 动态规划 背包问题的提高 —— 简单的有依赖性背包问题-金明的预算方案

 

     金明的预算方案

       有依赖性的背包正解为树形DP,对本人来说从未学过,但还好,这道题不用,因为每个主件只有两个附件且附件没有自己的附件,那么只需要考虑五种情况 :

       一. 只买主件

      二. 买主件和第一个附件

      三. 买主件和第二个附件

      四. 买主件和两个附件

      五. 什么都不买

      那么这道题就十分简单了。

      不过,该怎么确定主件的附件呢?

      首先要定义一个结构体数组,用来存放价格,重要度,是否为附件,编号,附件个数,附件编号

struct things{
    int v,w,q,num;//记录价格,重要度,是否为附件,编号 
    int s;//记录该零件的附件个数 
    int k[70];//记录该零件附件的编号 
}a[70];

       q表示附件的主件的编号,然后创立主件的附件集合(就是存附件的编号)  

       创建完过后,会发现有些主件没有附件,需要去判定是否有附件,不妨将没有附件的主见的附件认为是零,这样就更加简便,更好理解

for(int i = 1 ; i <= m ; i ++ )//初始化 
    {
        cin>> a[i].v >> a[i].w >> a[i].q ;
        a[i].w *= a[i].v ;
        a[i].num = i;//记录编号 
        if(a[i].q != 0)
        {
            a[ a[i].q ].s ++;//附件个数++ 
            a[ a[i].q ].k [a[a[i].q ].s] = a[i].num ;//找到主件,记录附件编号 
        }//为主件建立附件集合 
    }

       这样就创立了关于主件的附件集合,有了它之后,这道题就变成了一道简单的0.1背包问题,在DP时加一个过滤附件的判定,这道题就愉快的解决了。需要注意的是,在选择的时候,一定要记得比较一下是否有足够的钱去购买附件和主件,不然容易数组越界!!!(血的教训)

#include<iostream>
using namespace std;
int n , m , dp[50000] ;
struct things{
    int v , w , q , num ;//记录价格,重要度,是否为附件,编号 
    int s ;//记录该零件的附件个数 
    int k[70] ;//记录该零件附件的编号 
}a[70];
int max(int x , int y )
{
    if(x > y) return x ;
    return y ;
}
int main()
{
    cin>> n >> m ;
    for(int i = 1 ; i <= m ; i ++ )//初始化 
    {
        cin>> a[i].v >> a[i].w >> a[i].q ;
        a[i].w *= a[i].v ;
        a[i].num = i;//记录编号 
        if(a[i].q != 0)
        {
            a[ a[i].q ].s ++;//附件个数++ 
            a[ a[i].q ].k [a[a[i].q ].s] = a[i].num ;//找到主件,记录附件编号 
        }//为主件建立附件集合 
    }
    for(int i = 1 ;i <= m ; i ++ )//dp
    {
        for(int j = n ; j >= a[i].v ; j -- )
        {
            if( a[i].q == 0 )//判定是否为主件 
            {
                if( j >= a[i].v )//单独买主件 
                    dp[j]=max(dp[j],dp[j-a[i].v ] + a[i].w);
                    
                if(j >= a[ a[i].k[1] ].v + a[i].v )//买主件和第一个附件 
                    dp[j]=max(dp[j],dp[j-a[a[i].k [1]].v -a[i].v ] + a[a[i].k [1]].w + a[i].w );
                    
                if(j >= a[ a[i].k[2] ].v + a[i].v )//买主件和第二个附件 
                    dp[j]=max(dp[j],dp[j-a[a[i].k [2]].v -a[i].v ] + a[a[i].k [2]].w + a[i].w );
                    
                if(j >= a[a[i].k[1]].v + a[a[i].k [2]].v + a[i].v )//买主件和两个附件 
                    dp[j]=max( dp[j] , dp[j-a[a[i].k [1]].v -a[a[i].k [2]].v -a[i].v ] + a[a[i].k [1]].w + a[a[i].k [2]].w + a[i].w );
            }
        }
    }
    cout<< dp[n] ;
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值