物件捆绑 背包问题 动态规划 求解

  物件捆绑背包问题:给定N元钱,要购买一些器件。器件有主件和附件之分,也即主件可以单独购买,然而购买附件必须购买对应的主件。下表就是一些主件与附件的例子:

主件 附件
电脑      打印机、扫描仪
书柜 图书
书桌          台灯
工作椅

     把每件物品规定一个重要度,分为5等:用整数1~5表示,第5等最重要。在花费不超过N元(可以等于N元)的前提下,使每件物品的价格与重要度的乘积的总和最大。设第j件物品的价格为v[j],重要度为p[j],共选中了k件物品,编号依次为j1,j2,……,jk,则所求的总和为:v[j1]*p[j1]+v[j2]*p[j2]+ …+v[jk]*p[jk]。

  输入

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

  从第2行到第m+1行中,第j行给出了编号为j-1的物品基本数据,每行有3个非负整数: v  p  q(v:物品价格,p:物品重要度,q:主件还是附件。q=0为主件;q>0为附件,q是所属主件的编号)

  输出

    输出为不超过总钱数的物品的价格与其重要度乘积的总和的最大值。

  动态规划求解:

  1)思路:同一般的背包问题不同的是,在购买附件的同时必须要购买相应的主件。我们需要对主,附件做捆绑。每一种捆绑结果作为一种购买方式,之后同一般的背包问题

  例如:主件A,有附件B、附件C,则由数理统计的知识可知有4中购买方式,即(A,A+B,A+C,A+B+C)。

    附件个数为n-1时的购买方式个数为:

  2)主附件捆绑的数据结构选择:

  因为一件附件只有一个主件,为了捆绑的方便性,可以采用链表的形式。主件为头结点,拉链为附件节点。如下所示:

  3)问题求解

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
typedef struct node
{
    int price;  ///价格
    int priority;  ///重要程度
    struct node *next;
}Node;

typedef struct  ///拉链数据结构
{
    Node num[60];
}List;

int dp[360][32001];
int pos;    ///用于标记数量
int n,m;    ///总钱数和物品数

void input(List*);  ///物件情况输入,并构造主附件捆绑的数据结构(拉链法)
void preDP(List*);  ///进行主附件的捆绑
void exeDP(int,int);    ///执行动态规划

int main()
{
    List list;
    while(scanf("%d %d",&n,&m)!=EOF)
    {
        input(&list);
        preDP(&list);
        printf("%d\n",dp[m][n]);
    }
    return 0;
}

void input(List* list)
{
    int i;
    int v,p,q;  ///分别代表价格,重要程度,以及主件的编号
    Node *tmp;
    for(i=0;i<m;i++)
    {
        scanf("%d %d %d",&v,&p,&q);
        if(q==0)    ///主件
        {
            list->num[pos].price=v;
            list->num[pos].priority=p;
            list->num[pos].next=NULL;
            pos++;
        }
        else    ///附件
        {
            tmp=(Node*)malloc(sizeof(Node));
            tmp->price=v;
            tmp->priority=p;

            tmp->next=list->num[q-1].next;  ///使用头叉拉链法
            list->num[q-1].next=tmp;
        }
    }
}

void preDP(List *list)
{
    int i;
    int sumv,sumvp;
    Node *p=NULL,*tmp=NULL;
    m=-1;    ///捆绑物品个数计数,从0开始。

    for(i=0;i<pos;i++)  ///对每个主件开始的链
    {
        sumv=list->num[i].price;    ///只包括主件
        sumvp=list->num[i].price*list->num[i].priority;
        m++;
        exeDP(sumv,sumvp);

        p=list->num[i].next;
        while(p!=NULL)  ///包括主件+附件的情况
        {
            ///每次都要带主件
            sumv=list->num[i].price;
            sumvp=list->num[i].price*list->num[i].priority;
            tmp=p;
            while(tmp!=NULL)
            {
                sumv=sumv+tmp->price;
                sumvp=sumvp+tmp->price*tmp->priority;
                m++;
                exeDP(sumv,sumvp);
                tmp=tmp->next;
            }
            tmp=p;
            p=p->next;
            free(tmp);
        }
    }
}

void exeDP(int sumv,int sumvp)
{
    int i;
    for(i=0;i<=n;i++)
    {
        if(m==0)
        {
            if(sumv>i)
                dp[0][i]=0;
            else
                dp[0][i]=sumvp;
        }
        else
        {
            if(sumv>i)
                dp[m][i]=dp[m-1][i];
            else
                dp[m][i]=dp[m-1][i]>(dp[m-1][i-sumv]+sumvp)? dp[m-1][i]:(dp[m-1][i-sumv]+sumvp);
        }
    }
}

 

 

时间: 2024-10-29 06:34:46

物件捆绑 背包问题 动态规划 求解的相关文章

背包问题 matlab-背包问题Matlab动态规划求解程序报错 求指导 万分感谢!!

问题描述 背包问题Matlab动态规划求解程序报错 求指导 万分感谢!! KnapSack1(v,w,n,W) for w=0 to W V[0,w]=0; %将二维数组第一行赋值全零 for i=1 to n for w=0 to W if w_i<=w V[i,w]=max(V[i-1,w],v_i+V[i-1,w-w_i]) %V[i,w]记录权值至少为w且最大的子集{1,2,...,n} else V[i,w]=V[i-1,w]; Return V[i,W]; end end end e

概率问题,动态规划求解

问题描述 概率问题,动态规划求解 大神们,用动态规划怎么解这道题呀? 问题描述 生成n个∈[a,b]的随机整数,输出它们的和为x的概率. 输入格式 一行输入四个整数依次为n,a,b,x,用空格分隔. 输出格式 输出一行包含一个小数位和为x的概率,小数点后保留四位小数 样例输入 2 1 3 4 样例输出 0.3333 数据规模和约定 对于50%的数据,n≤5. 对于100%的数据,n≤100,b≤100. 解决方案 http://zhidao.baidu.com/link?url=DusTYd_4

字符串相似度算法 递归与动态规划求解分析

1.概念 编辑距离,指的是两个字符串之间,由一个转换成另一个所需的最少编辑操作次数.许可的编辑操作包括:(1)将一个字符替换成另一个字符,(2)插入一个字符,(3)删除一个字符. 相似度,等于"编辑距离+1"的倒数. 2.分析 设有字符串a[0...n],b[0...m]. (1)当a[i]=b[j]时,说明这时候不需要编辑操作.编辑距离保持,即f(i,j)=f(i-1,j-1) (2)当a[i]!=b[j]时,可以有三种编辑操作. 其中删除和插入操作,只对一个下标i或者j产生影响.如

矩阵连乘最优结合 动态规划求解

1.引言  多矩阵连乘 对于一般的矩阵乘法来说,如矩阵A(m,n)与矩阵B(n,p)相乘需要进行的加法次数为m*n*p次乘法. 由于矩阵乘法满足结合律,因此矩阵相乘的结合性,会影响整个计算表达式的乘法执行次数. 如下面的例子,其中A(10,5).B(5,20).C(20,3): (1) ((AB)C) 执行乘法次数为1300次 (2) (A(BC)) 执行乘法次数为450次 2.求最优的矩阵结合表达式 (1)设矩阵连乘积AiAi+1-Aj简记为A[i:j],设最优计算次序在Ak和Ak+1之间断开

动态规划总结

动态规划 终于来到了算法设计思想中最难,也最有趣的这部分,在去年的google笔试中,7道算法设计题有2道动态规划(Dynamic Programming). 看了这么久的算法,这部分也是唯一感觉到了比较难的地方, 从这篇文章开始,将花连续的篇幅来讨论一些动态规划的问题.这包括书上介绍过的计算二项式系数,Warshall算法求传递闭包,Floyd算法求完全最短路径,构造最 有二叉查找树,背包问题和记忆功能.也包括一些其他问题的解题报告(动态规划确实很难,对这一章的内容,我将搜索一些其他类型的问题

0-1背包问题思想的算法题目

题目概述 经过抽签选择, 小智将军第一个进入考场. 菜虫: (身上散射出华贵(?)的光芒)欢迎你, 第一位挑战者!! 小智: --(走到菜虫身后, 关灯)女王陛下, 虽然我们国家现在很富裕, 但也请您不要浪费电来用这么大功率的灯泡. 菜虫(汗): 啊啊~~爱卿所言甚是~~那么, 你的题目是--我们的情报组织探听到敌人的重要将领--小飞侠星期天会邀他的灵儿妹妹到公园去玩. 公园里有很多娱乐项目, 可并不是每一项他们都喜欢, 所以他们对每一项都进行了"喜欢度"的评分. 因为小飞侠也是一个了

求解一个关于java的问题

问题描述 求解一个关于java的问题 这里的temp在前面没有被定义,也没声明,为什么能被使用??如图 解决方案 定义对象的同时可以给对象进行一些赋值的操作 解决方案二: 定义了啊同学Course temp = xxxx那不是定义么 解决方案三: 你想表达啥?没懂你意思呢?Course temp 不是在声明吗? 解决方案四: 一个问题求解Java动态规划求解最长公共子串问题一个搜索问题的求解 解决方案五: 看来这个是连对象都不知道是什么的同志 解决方案六: 定义了 Course cr = new

五大常用算法之二:动态规划算法(DP)

一.基本概念     动态规划过程是:每次决策依赖于当前状态,又随即引起状态的转移.一个决策序列就是在变化的状态中产生出来的,所以,这种多阶段最优化决策解决问题的过程就称为动态规划. 二.基本思想与策略     基本思想与分治法类似,也是将待求解的问题分解为若干个子问题(阶段),按顺序求解子阶段,前一子问题的解,为后一子问题的求解提供了有用的信息.在求 解任一子问题时,列出各种可能的局部解,通过决策保留那些有可能达到最优的局部解,丢弃其他局部解.依次解决各子问题,最后一个子问题就是初始问题的解.

C++动态规划之背包问题解决方法_C 语言

本文实例讲述了C++动态规划之背包问题解决方法.分享给大家供大家参考.具体分析如下: 问题描述: 背包的最大容量为W,有N件物品,每件物品重量为w,价值为p,怎样选择物品能使得背包里的物品价值最大? 输入:10 3   (W,N) 4 5   (w,p) 6 7   (w,p) 8 9   (w,p) 实现代码: #include <stdio.h> #define THING 20 #define WEIGHT 100 int arr[THING][WEIGHT]; /* 背包容量为weig