• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
生若秋叶
gonna to be a designer,a designer of my life!!
博客园    首页    新随笔    联系   管理    订阅  订阅

背包问题(Knapsack problem)采用动态规划求解

问题说明:

假设有一个背包的负重最多可达8公斤,而希望在背包中装入负重范围内可得之总价物
品,假设是水果好了,水果的编号、单价与重量如下所示:
0
李子
4KG
NT$4500
1
苹果
5KG
NT$5700
2
橘子
2KG
NT$2250
3
草莓
1KG
NT$1100
解法背包问题是关于最佳化的问题,要解最佳化问题可以使用「动态规划」 (Dynamicprogramming) ,从空集合开始,每增加一个元素就先求出该阶段的最佳解,直到所有的元素加入至集合中,最后得到的就是最佳解。

下面我们看下代码:

/*
问题:
假设有一个背包的负重最多可达8公斤,而希望在背包中装入负重范围内可得之总价物品
算法说明:
采用动态规划,在当前阶段求解出最好的解,如此反复
日期:2013/8/18
张威
*/

#include <iostream>
#include <time.h>
using namespace std;

#define MAXSIZE 8

//定义全局变量
char name[5][5] = {"李子","苹果","橘子","草莓","甜瓜"};//水果名称
int wight[5] = {4,5,2,1,6};//单个水果所占斤数
int price[5] = {4500,5700,2250,1100,6700};//单个水果的价值
int perkg_price[5];//每斤水果的价钱
int perkg_num[5] = {0,1,2,3,4};

void GetNmae(int num)
{
    for (int i = 0;i <= 4;i++)
    {
        cout<<name[num][i];
    }
}

void GetBestAnswer(int currentwigh)
{
    //判断递归终止条件
    if (currentwigh >= MAXSIZE)
    {
        cout<<"包裹已经满了,无法再装进东西"<<endl;
    }
    else
    {
        //check用来表证到底剩下来的物品里面还有没有能装进去背包里的
        bool check = true;
        int i = 0;
        for (;i <= 4;i++)
        {
            //若是没有进入到这个条件内,说明剩下来的物品的重量都超过了背包剩余重量,到此结束.否则i就代表当前所能选中的最优解
            if (wight[perkg_num[i]] <= MAXSIZE-currentwigh)
            {
                check = false;
                break;
            }
        }
        if (check == true)
        {
            cout<<"已经装不进去任何水果了"<<endl;
        }
        else
        {
            //得到最优解,并且将当前重量增加,进入下一次递归
            currentwigh += wight[perkg_num[i]];
            cout<<"购买了";
            GetNmae(perkg_num[i]);
            cout<<endl;
            GetBestAnswer(currentwigh);
        }
    }
}


int main()
{
    //计算出每斤水果的价钱,便于动态规划时求出当前最佳解
    for (int i = 0;i <= 4;i++)
    {
        perkg_price[i] = price[i] / wight[i];
    }
    //对perkg_num进行排序,同时保证单价和perkg_num之间的一一对应关系.即两个数组要同时变化
    //采用的是冒泡排序,在元素进行交换时perkg_num和perkg_price同时变化
    for (int i = 0;i <= 3;i++)
    {
        for (int j = i;j <= 3;j++)
        {
            if (perkg_price[j] < perkg_price[j+1])
            {
                int temp1 = perkg_price[j];
                int temp2 = perkg_num[j];
                perkg_price[j] = perkg_price[j+1];
                perkg_price[j+1] = temp1;
                perkg_num[j] = perkg_num[j+1];
                perkg_num[j+1] = temp2;
            }
        }
    }
    //开始计算求解
    GetBestAnswer(0);
    return 0;
}
背包问题

在这里,算法的主要思想有两个:1.通过冒泡排序得到一个单价表,并将物品的ID与之配对起来.这样我们在每次的递归中通过ID找到物品的相应属性,筛选出当前步骤的最优解出来

2.通过递归,传递当前的重量,得到还剩余的重量,根据前面的单价表,筛选出可选的最优解,然后将重量变化进入下一次递归.

这是最大空间为8的运行结果:                                              这是最大空间为29的运行结果:

 下面附上指导书上面的代码:

#include <stdio.h>
#include <stdlib.h>
#define LIMIT 8
// 重量限制
#define N 5
// 物品种类
#define MIN 1
// 最小重量
struct body {
char name[20];
int size;
int price;
};
背
包
负
重
1
2
3
4
5
6
7
8
valu
e
110
0
225
0
335
0
450
0
570
0
680
0
795
0
905
0
item
3
2
3
0
1
3
2
3
背
包
负
重
1
2
3
4
5
6
7
8
valu
e
110
0
225
0
335
0
450
0
570
0
680
0
795
0
905
0
item
3
2
3
0
1
3
2
3
typedef struct body object;
int main(void) {
int item[LIMIT+1] = {0};
int value[LIMIT+1] = {0};
int newvalue, i, s, p;
object a[] = {{"李子", 4, 4500},
{"苹果", 5, 5700},
{"橘子", 2, 2250},
{"草莓", 1, 1100},
{"甜瓜", 6, 6700}};
for(i = 0; i < N;i++) {
for(s = a[i].size; s <= LIMIT;s++) {
p = s - a[i].size;
newvalue = value[p] + a[i].price;
if(newvalue > value[s]) {// 找到阶段最佳解
value[s] = newvalue;
item[s] = i;
}
}
}
printf("物品\t价格\n");
for(i = LIMIT;i >= MIN;i = i - a[item[i]].size) {
printf("%s\t%d\n",
a[item[i]].name, a[item[i]].price);
}
printf("合计\t%d\n", value[LIMIT]);
return 0;
}
Java
class Fruit {
private String name;
private int size;
private int price;
public Fruit(String name,int size, int price){
this.name = name;
this.size = size;
this.price = price;
}
public String getName(){
return name;
}
public int getPrice(){
return price;
}
public int getSize() {
return size;
}
}
public class Knapsack {
public static void main(String[] args){
final int MAX = 8;
final int MIN = 1;
int[] item = new int[MAX+1];
int[] value = new int[MAX+1];
Fruit fruits[] = {
new Fruit("李子", 4, 4500),
new Fruit("苹果", 5, 5700),
new Fruit("橘子", 2, 2250),
new Fruit("草莓", 1, 1100),
new Fruit("甜瓜", 6, 6700)};
for(int i = 0; i < fruits.length;i++) {
for(int s = fruits[i].getSize(); s <= MAX;s++){
int p = s - fruits[i].getSize();
int newvalue = value[p] +
fruits[i].getPrice();
if(newvalue > value[s]) {// 找到阶段最佳解
value[s] = newvalue;
item[s] = i;
}
}
}
System.out.println("物品\t价格");
for(int i = MAX;
i >= MIN;
i = i - fruits[item[i]].getSize()) {
System.out.println(fruits[item[i]].getName()+
"\t" + fruits[item[i]].getPrice());
}
System.out.println("合计\t" + value[MAX]);
}
}
指导书上面的代码

我居然没想到使用结构体,失策失策,都没用什么高级点的数据结构,看起来貌似很复杂的样子.明天再看

posted @ 2013-08-17 04:46  HappyCoder  阅读(1087)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3