背包问题 --- 蛮力法,动态规划

背包问题 --- 蛮力法,动态规划

问题描述

给定重量分别为,价值分别为的n件物品,和一个承重为W的背包。求这些物品中一个最有价值的子集,并能装到背包中。

蛮力法

背包问题的蛮力解法是穷举这些物品的所有子集,找出能够装到背包中的所有子集,并在这些子集中找出价值最大的子集。

//背包问题:蛮力法
#include <iostream>
#include <cstdio>
#define maxx 9999
using namespace std;
int n;//货物的总个数
int weight;//背包承受上限
int value = 0;//最大价值
int sum_w = 0;//重量
int sum_v = 0;//价值
int r[maxx];//存储子集
int count;
struct node{
    int weight;//重量
    int value;//价值
    bool flag=false;//标记是否被挑选
};
node pack[maxx];
int recursion(int x)
{
    //判断重量是否超过背包承受上限
    if(sum_w > weight)
    {
        return 0;
    }
    //判断最大价值
    if(sum_v > value)
    {
        value = sum_v;
        count = 0;
        //将最大价值所对应的子集放入r中
        for(int i=0;i<n;i++)
        {
            if(pack[i].flag)
            {
                r[count++] = i;
            }
        }
    }
    for(int i=x;i<n;i++)
    {
        sum_v += pack[i].value;
        sum_w += pack[i].weight;
        pack[i].flag = true;
        recursion(i+1);
        //回溯
        sum_v -= pack[i].value;
        sum_w -= pack[i].weight;
        pack[i].flag = false;
    }   
}

int main()
{
    cout << "请输入货物的总数量以及背包能承受的最大重量:" << endl;
    cin >> n >> weight;
    cout << "请依次输入每件物品的重量和价值:" << endl;
    for(int i=0;i<n;i++)
    {
        cin >> pack[i].weight >> pack[i].value;
    }
    recursion(0);
    cout << "最大总价值的子集为: ";
    for(int i=0;i<count;i++)
    {
        cout << r[i]+1 << "  ";
    }
    cout << endl << "最大总价值最大可以为: " << value << endl;
    return 0;
}

动态规划

  • 基本思想

用weight[]数组存储每件物品的重量,value[]数组来存储每件物品的价值,用v[i][j]来表示i件物品在最大承受重量为j时的最大价值。
在背包问题中我们要思考的主要是选不选择这个物品。
对于一个物品,只有两种情况:

  1. 第i件不放进背包,这时总价值为v[i-1][j];
  2. 第i件放进背包,这时总价值为v[i][j-weight[i]]+value[i];

所以我们由此得出结论v[i][j] = max(v[i][j],v[i][j-weight[i]]+value[i]);
当背包容量为0时,v[i][0]=0;
当物品数量为0时,v[0][j]=0;
当然,在我们考虑是否放进去时,是有前提的。即要考虑物品的重量以及背包剩余容量。

  • 当物品重量小于背包剩余容量时:
    v[i][j] = max(v[i][j],v[i][j-weight[i]]+value[i]);
  • 当物品重量大于背包剩余容量时:
    v[i][j] = v[i][j];

代码演示:

#include <iostream>
#include <cstdio>
#include <algorithm>
#define maxx 10000
using namespace std;
int n;//货物的总数量
int w;//背包能承受的最大重量
int value[maxx];//记录每件货物的价值
int weight[maxx];//记录每件货物的重量
int v[maxx][maxx];//记录一定承受重量对应的最大价值
int x[maxx];//记录最大价值时有哪些物品
int num = 0;
int main()
{
    cout << "请输入货物的总数量以及背包能承受的最大重量:" << endl;
    cin >> n >> w;
    cout << "请依次输入每件物品的重量和价值:" << endl;
    for(int i=0;i<n;i++)
    {
        cin >> weight[i] >> value[i] ;
    }
    //初始化dp表v[][]的第0列和第0行
    for(int i=0;i<=n;i++)
    {
        v[i][0] = 0;
    }
    for(int i=0;i<=w;i++)
    {
        v[0][i] = 0;
    }
    //通过遍历判断i件物品在最大承受重量为j时的最大价值
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=w;j++)
        {
            if(j < weight[i])
            {
                v[i][j] = v[i-1][j];   
            }
            else
            {
                v[i][j] = max(v[i-1][j],v[i-1][j-weight[i]]+value[i]);
            }
        }
    }
    //记录最大价值时有哪些物品
    for(int i=n,j=w;i>0;i--)
    {
        if(v[i][j]>v[i-1][j])
        {
            x[num ++] = i;
            j = j - weight[i];
        }
    }
    //输出
    cout << "最大总价值的子集为: ";
    for(int i=num-1;i>=0;i--)
    {
        cout << x[i]+1 << " ";
    }
    cout << endl << "最大价值为: " << v[n][w]<< endl;
    return 0;   
}

运行结果如下:

当然,这个题也可以用一位数组来做:

//背包问题:动态规划
#include <iostream>
#include <cstdio>
#include <algorithm>
#define maxx 9999
using namespace std;
int n;
int weight[maxx];
int value[maxx];
int w;
int v[maxx];
int main()
{
    cout << "请输入货物的总数量以及背包能承受的最大重量:" << endl;
    cin >> n >> w;
    cout << "请依次输入每件物品的重量和价值:" << endl;
    for(int i=1;i<=n;i++)
    {
        cin >> weight[i] >> value[i];
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=w;j>=weight[i];j--)
        {
            v[j] = max(v[j-weight[i]]+value[i],v[j]);           
        }
    }
    cout << "最大价值为: "<< v[w] << endl;
    return 0;
}

运行结果如下:

猜你喜欢

转载自blog.csdn.net/qq_41879343/article/details/89282039