Algorithm学习笔记 --- 金明的预算方案

来源:互联网 发布:在线真心话大冒险软件 编辑:程序博客网 时间:2024/05/16 06:16

金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房间。更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过N元钱就行”。今天一早金明就开始做预算了,他把想买的物品分为两类:主件与附件,附件是从属于某个主件的,下表就是一些主件与附件的例子:

主件

附件

电脑

打印机,扫描仪

书柜

图书

书桌

台灯,文具

工作椅

如果要买归类为附件的物品,必须先买该附件所属的主件。每个主件可以有0个、1个或2个附件。附件不再有从属于自己的附件。金明想买的东西很多,肯定会超过妈妈限定的N元。于是,他把每件物品规定了一个重要度,分为5等:用整数1~5表示,第5等最重要。他还从因特网上查到了每件物品的价格(都是10元的整数倍)。他希望在不超过N元(可以等于N元)的前提下,使每件物品的价格与重要度的乘积的总和最大。

设第j件物品的价格为v[j],重要度为w[j],共选中了k件物品,编号依次为j1j2,……,jk,则所求的总和为:

v[j1]*w[j1]+v[j2]*w[j2]+ +v[jk]*w[jk]。(其中*为乘号)

请你帮助金明设计一个满足要求的购物单。

1行,为两个正整数,用一个空格隔开:

N m

(其中N<32000)表示总钱数,m<60)为希望购买物品的个数。)

从第2行到第m+1行,第j行给出了编号为j-1的物品的基本数据,每行有3个非负整数

v p q

(其中v表示该物品的价格(v<10000),p表示该物品的重要度(1~5),q表示该物品是主件还是附件。如果q=0,表示该物品为主件,如果q>0,表示该物品为附件,q是所属主件的编号)

只有一个正整数,为不超过总钱数的物品的价格与重要度乘积的总和的最大值(<200000

1000 5

800 2 0 

400 5 1

300 5 1

400 3 0

500 2 0

2200




解题分析:

此题我第一次看到以为就是简单的01背包或者多维背包,后来做了几次都是WA,才静下心来好好审题,对于此题的一个研究点是,到底买的是主件还是附件,如果是主件,还买接下来的几个附件了,0个?1个?2个?(这里还好题里给出最多的是两个)如果是附件就得买相应的主件。

因此,此处多了几个条件:

W1=v[i]                              (只买主件)

W2=v[i]+v[q1[i]]                       (买主件和第一个附件)

W3=v[i]+v[q2[i]]                        (买主件和第二个附件)

W4=v[i]+v[q1[i]]+v[q2[i]]                (买主件和那两个附件)

然后

在动态转移方程的时候有一点是注意这里不是单一的dp[j]=max(dp[j],dp[j-w[i]]+v[i]);

此处是重要度和价格的成绩。

因此此题的乘积相当于原背包的价值量,适当的更改就好。





代码如下:

#include<cstdio>
#include<iostream>
#include<cstring>
#define MAXN 3300
using namespace std;
int i, j, k;
int dp[MAXN];
int v[70], w[70], q[70];
int c[70][3], tw[5], tv[5], cnt;
int N, m;


void pack(int i)                                            //此处是捆绑函数,就是main函数中判断是主件的情况进入此函数
{
    if(c[i][0] == 0)                                        //是否买一个附件,下面以此类推
    {
        tv[1] = v[i];                                       //此处买的价格进行替换,下面以此类推,如果买多个就把价钱加起来
        tw[1] = v[i] * w[i];                                //此处为所说的重要度与价钱的乘积,下面以此类推
        cnt = 1;                                            //此处为一共买几个的个数,下面以此类推
    }
    else if(c[i][0] == 1)                                   //是否买两个附件
    {
        tv[1] = v[i];
        tw[1] = v[i] * w[i];
        tv[2] = v[i] + v[c[i][1]];
        tw[2] = v[i] * w[i] + v[c[i][1]] * w[c[i][1]];
        cnt = 2;
    }
    else                                                    //是否买三个主件
    {
        tv[1] = v[i];
        tw[1] = v[i] * w[i];
        tv[2] = v[i] + v[c[i][1]];
        tw[2] = v[i] * w[i] + v[c[i][1]] * w[c[i][1]];
        tv[3] = v[i] + v[c[i][2]];
        tw[3] = v[i] * w[i] + v[c[i][2]] * w[c[i][2]];
        tv[4] = v[i] + v[c[i][1]] + v[c[i][2]];
        tw[4] = v[i] * w[i] + v[c[i][1]] * w[c[i][1]] + v[c[i][2]] * w[c[i][2]];
        cnt = 4;
    }
}


int main()
{
        scanf("%d%d",&N,&m);                        //输入两个数,N总的钱数,m,总的物品个数
        memset(c,0,sizeof(c));                      //对c数组进行都为0的初始化
        for(i = 1; i <= m; i++)
        {
            scanf("%d%d%d",&v[i],&w[i],&q[i]);      //依次输入每组的价格,重要度,主件还是附件
            if(q[i])                                //if(q[i]>0则为附件,q[i]=0为主件,
                                                    //if()语句中如果()中的语句>0则成立,如果=0则不成立)
                c[q[i]][++c[q[i]][0]] = i;
        }


        memset(dp, 0, sizeof(dp));                  //将dp做赋值为0的初始化
        for(i = 1; i <= m; i++)
        {
            if(q[i])
                continue;                           //此处同上
            pack(i);                                //如果买的是主件则进入附件捆绑函数进行判断
            //状态转移方程01背包
            for(j = N; j >= v[i]; j--)
            {
                for(k = 1; k <= cnt; k++)           //cnt代表一共买多少个东西
                {
                    if(j >= tv[k])
                        dp[j] = max(dp[j], dp[j-tv[k]] + tw[k]);    //此处用tw[k]每件的价钱与重要度的成绩,替换经典转换方程中的value[];
                }
            }
        }
        cout<<dp[N];
    return 0;
}


0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 小米手机安卓系统耗电量大怎么办? 苹果5s充不进去电怎么办 苹果手机6s返回键失灵怎么办 本人被骗同时被利用骗了别人怎么办 京东取消订单后货到了该怎么办 京东电信日租卡流量顶置了怎么办 苹果6s进水后闪光灯不亮怎么办 华为手机情景义停车事项过期怎么办 拼多多付款后商品下架了怎么办 淘宝上买化妆品买到假货了怎么办 找苹果官网解id发票丢了怎么办 客人已交订金但要取消宴席怎么办 京东买的小米电视碎屏了怎么办 京东购买的电视碎屏了怎么办 淘宝上买手机不能用不给退怎么办 天猫申请退货退款卖家不处理怎么办 在淘宝买到货到付款的假苹果怎么办 跟朋友买手机买到假货怎么办 在淘宝网上买到不合格的产品怎么办 淘宝打假师打了我的店铺怎么办 收藏品公司关门跑路员工怎么办 客户快递签收后说货物短缺怎么办 京东商城买东西商家不换货怎么办 在商场买东西过几天就降价了怎么办 天猫买东西不退货不退款怎么办 买买8p美版的怎么办 京东金条银行卡被冻结还不了怎么办 在瑞士刚买的浪琴手表不走了怎么办 刚买的手表表镜有划痕 怎么办 唯品会上买的手表有质量问题怎么办 我买的对方材料没开票给我怎么办 给对方修完车车主不给发票怎么办 买苹果手机花呗额度不够怎么办 苹果手机用别人的手机卡激活怎么办 小米商城花呗分期额度不够怎么办 淘宝已经形成订单商家不发货怎么办 小米商城退款后又想买了怎么办 淘宝退货退款后不想退了怎么办 在转转的商品被屏了怎么办 不懂如何挑选适合自己的衣服怎么办 淘宝购买商品给顾客造成损失怎么办