• 背包问题(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
    
    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
    
    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("物品	价格
    ");
    for(i = LIMIT;i >= MIN;i = i - a[item[i]].size) {
    printf("%s	%d
    ",
    a[item[i]].name, a[item[i]].price);
    }
    printf("合计	%d
    ", 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("物品	价格");
    for(int i = MAX;
    i >= MIN;
    i = i - fruits[item[i]].getSize()) {
    System.out.println(fruits[item[i]].getName()+
    "	" + fruits[item[i]].getPrice());
    }
    System.out.println("合计	" + value[MAX]);
    }
    }
    指导书上面的代码

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

  • 相关阅读:
    windows上docker部署springboot多实例
    oracle 如何搜索当前用户下所有表里含某个值的字段?
    VS2010/OpenGL配置
    (译)Minimal Shader(最小的着色器)
    (译)Cg Programming/Unity(Cg编程/Unity)
    (转)在Unity3D中控制动画播放
    Unity3d中使用assetbundle
    C# 操作 sqlite
    Unity3d网格合并
    在Unity3d中解析Lua脚本的方法
  • 原文地址:https://www.cnblogs.com/color-my-life/p/3263815.html
Copyright © 2020-2023  润新知