P1064 金明的预算方案

传送门

思路:

  有条件的 01背包(有依赖的背包)。

  可分为四种情况来做 01背包 :①不买主件 ②买主件 ③买主件+副件1 ④买主件+副件2 ⑤买主件+副件1+副件2

  转移条件:

  ①没有附件,按最基本的 01背包来做。  

  ②该附件和主件的重量(为区分价格和价值,接下来的所有分析都按背包理解)之和 ≤ 现在在判断的 j (背包剩余容量)(也是按照 01背包 的模板做)

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<cstdlib>
#include<queue>
#include<vector>
#include<deque>
#include<stack>
#include<map>
#include<set>
using namespace std;
#define maxn 40000
int m,n,v,p,q;//m背包容量,n物品数量,v物品价格,p重要程度,q判断是否为主件 
int mw[maxn],mv[maxn],fw[maxn][3],fv[maxn][3];
//mw主件重量,mv主件价值,fw主件对应的附件重量,fv主副价值,n总重量,m总个数   
int f[maxn];
inline int read()
{
    int kr=1,xs=0;
    char ls;
    ls=getchar();
    while(!isdigit(ls))
    {
        if(!(ls^45))
        kr=-1;
        ls=getchar();
    }
    while(isdigit(ls))
    {
        xs=(xs<<1)+(xs<<3)+(ls^48);
        ls=getchar();
    }
    return kr*xs;
}
int main()
{
    n=read();m=read();
    for(int i=1;i<=m;i++)
    {
        v=read();p=read();q=read();
        if(!q)//如果是主件
        {
            mw[i]=v;//主件重量 
            mv[i]=v*p;//主件价值与重量乘积   
        }
        else//如果是附件
        {
            fw[q][0]++;//记录主件的附件个数(只记录在fw就行,fv那里没用 
            fw[q][fw[q][0]]=v;//主件的个数是用来确定该附件应该填在第一个还是第二个格子里  
            fv[q][fw[q][0]]=v*p;//(是第一个还是第二个附件)   
        }
    }
    for(int i=1;i<=m;i++)
        for(int j=n;j>=mw[i];j--)//01背包模板   
        { //每一个if的前提是背包能不能装下该物品  
            f[j]=max(f[j],f[j-mw[i]]+mv[i]);//情况1:只要主件和什么都不要比较  
            if(j>=mw[i]+fw[i][1])//情况2:主件和附件1 和上面选出的较大值比较   
                f[j]=max(f[j],f[j-mw[i]-fw[i][1]]+mv[i]+fv[i][1]);
            if(j>=mw[i]+fw[i][2]) //情况3:主件和附件2 和上面选出的较大值比较   
                f[j]=max(f[j],f[j-mw[i]-fw[i][2]]+mv[i]+fv[i][2]);
            if(j>=mw[i]+fw[i][1]+fw[i][2])//情况4:都要   
                f[j]=max(f[j],f[j-mw[i]-fw[i][1]-fw[i][2]]+mv[i]+fv[i][1]+fv[i][2]);
        }
    printf("%d\n",f[n]);//输出  
return 0;
}

 

posted @ 2018-09-25 21:17  落笔映惆怅丶  阅读(134)  评论(0编辑  收藏  举报