首页 > 其他分享 >蛮力法解 01 背包问题

蛮力法解 01 背包问题

时间:2022-10-15 21:27:42浏览次数:88  
标签:状态 01 int state 蛮力 物品 背包 放入 法解

本文发表在博客园乌漆 WhiteMoon(https://www.cnblogs.com/linfangnan/),只要不是在博客园看到这篇文章的都是爬虫的哈。

目录

蛮力法

蛮力法也称穷举法或枚举法,是一种简单直接地解决问题的方法,常常直接基于问题的描述,所以蛮力法也是最容易应用的方法。蛮力法所依赖的基本技术是遍历,也称扫描,即采用一定的策略依次理待求解问题的所有元素,从而找出问题的解。依次处理所有元素是蛮力法的关键,为了避免陷人重复试探,应保证处理过的元素不再被处理。

01 背包问题

01 背包是在 N 件物品取出若干件放在可容纳的重量为 W 的背包里,每件物品的重量为 w1, w2, …, wn,与之相对应的价值为 v1, v2, …, vn。01 背包是背包问题中最简单的问题,它的约束条件是给定几种物品,每种物品有且只有一个,并且有价值和重量两个属性。

代码编写

状态表示

首先需要先枚举出所有可能状态,通过迭代遍历这些状态后得出将哪些物品放入背包能获得最大的价值。类似于 IPv4 的地址,使用点分十进制的方式利用一个码串来标识唯一一台网络设备或主机。其中 8 为二进制对应十进制的取值范围为 0 ~ 255,可以描述 256 个状态。

由于每个物品对于背包而言只有放入与否 2 个状态,可以考虑使用 1 位二进制来表示,1 表示放入,0 表示不放入。对于 N 个物品,可以用一个 N 位的二进制码串来说明哪些物品放入背包。假设二进制的高位表示物品序号较低的物品,低位表示物品序号较高的物品,如下是当 N = 4 时的一些状态表示的含义。

0000:所有物品都不放入
0001:放入物品 4
0010:放入物品 3
1100:放入物品 1、2
1111:4 个物品全部放入

一个二进制码串可以使用顺序表进行简单实现,状态需要变换时只需要对最低位加一,然后依次判断每一位的状态。若低位等于 2,就需要向高位进 1 后归为 0,由低位向高位遍历即可完成状态转换。例如此处我使用 C++ 的 vector 进行实现,向量 state 的初始状态为 0000,最终状态为 1111。

vector<int> state(items_num, 0);    // 某个状态放入的物品
// 设二进制码串位数为 n,则需要经过 2^n 次迭代 
for(int i = 1; i < pow(2, items_num); i++)
{
    //更新当前状态
    state[0] += 1;    // 最低位加 1
    for(int j = 0; j < items_num; j++)
    {
        // 逢 2 进位
        if(state[j] == 2)
        {
            state[j] = 0;
            state[j + 1] += 1;
        }
    }
}

约束条件

现在我们已经能描述背包放入物品的所有状态了,接下来只需要结合约束条件判断最优解即可。为了记录最优状态和最大的价值量,我们需要定义一些变量来记录,如下是我用到的一些变量和用来判断是否需要更新状态的分支结构。

int max_value = 0;    // 记录最大价值 
int now_weight;       // 某个状态时的重量 
int now_value;        // 某个状态的价值 
vector<int> max_state(state);       // 最大价值时放入的物品 
vector<int> state(items_num, 0);    // 某个状态放入的物品

// 判断这种取法是否没超过容量且价值更高,是就更新最佳状态
if(now_weight <= pack_capacity && now_value > max_value)
{
    max_value = now_value;
    max_state.assign(state.begin(), state.end());    // 复制vector容器 
}

完整代码

综合上述的思想,加上输入输出和过程处理的其他代码,得到的完整代码如下。

#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
int main()
{
    // 输入物品数量和背包容量 
    int items_num;        //物品数量 
    int pack_capacity;    //背包容量 
    cout << "物品的数量为:"; 
    cin >> items_num;
    cout << "背包的容量为:"; 
    cin >> pack_capacity;
	
    // 输入每个物品的重量和价值 
    vector<int> weights(items_num);
    vector<int> values(items_num);
    for(int i = 0; i < items_num; i++)
    {
        cout << "物品" << i << "的重量为:";
        cin >> weights[i];
        cout << "物品" << i << "的价值为:";
        cin >> values[i];
    }
    
    // 蛮力法求解01背包问题 
    int max_value = 0;    // 记录最大价值 
    int now_weight;       // 某个状态时的重量 
    int now_value;        // 某个状态的价值 
    vector<int> max_state(state);       // 最大价值时放入的物品 
    vector<int> state(items_num, 0);    // 某个状态放入的物品
    // 设物品数量为 n,则需要经过 2^n 次迭代 
    for(int i = 1; i < pow(2, items_num); i++)
    {
        now_weight = 0;
        now_value = 0;
        //更新当前状态,并计算该状态下的价值 
        state[0] += 1;
        for(int j = 0; j < items_num; j++)
        {
            // 逢2进位,1表示放入背包,0表示不放入(不处理) 
            if(state[j] == 2)
            {
                state[j] = 0;
                state[j + 1] += 1;
            }
            else if(state[j] == 1)
            {
                now_weight += weights[j];
                now_value  += values[j];
            }
        }
        // 判断这种取法是否没超过容量且价值更高,是就更新最佳状态
        if(now_weight <= pack_capacity && now_value > max_value)
        {
            max_value = now_value;
            max_state.assign(state.begin(), state.end());    // 复制vector容器 
        }
    }
	
    // 输出结果 
    cout << "\n该背包能存放物品的最大价值为:" << max_value << endl;
    cout << "物品分别是:";
    for(int i = 0; i < items_num; i++)
    {
        if(max_state[i] == 1)
        {
            cout << "物品" << i << " "; 
        }
    }
    return 0;
}

测试数据

测试数据 1

4 个物品,重量和质量信息如下,容量为 10 的背包。

物品序号 重量 质量
0 7 42
1 3 12
2 4 40
3 5 25

测试数据 2

8 个物品,重量和质量信息如下,容量为 25 的背包。

物品序号 重量 质量
0 7 42
1 5 31
2 3 12
3 2 7
4 4 40
5 8 41
6 6 25
7 9 40

标签:状态,01,int,state,蛮力,物品,背包,放入,法解
From: https://www.cnblogs.com/linfangnan/p/16794938.html

相关文章

  • 软光栅渲染器开发01-背景介绍以及第一个三角形
    1.为什么是软光栅渲染器正常来讲,一个有志于进行游戏或者图形开发的人,在实际的生产环境中,大多是依赖于游戏引擎或者常见图形API(OpenGL,DirectX,Vulkan)的封装来进行工作......
  • 01项目了解
    1.前后端交互   2.dto:数据传输对象,不往数据库里存储,用来接收页面过来的数据  公共分页请求对象======importlombok.Setter;/***公共分页请求对象*/......
  • 018——常量
    常量常量概述和基本作用常量是使用了publicstaticfinal修饰的成员变量,必须有初始化值,而且执行的过程中其值不能被改变。常量名的命名规范:英文单词全部大写,多个单词下......
  • 动力节点——day01
    eclipse的快捷键:1.ctrl+d删除一行2.ctrl+1进行纠错3.alt+/自动补全4.单行注释ctrl+/5.多行注释ctrl+shift+/取消ctrl+shift+\6.按住ctrl同时选中某个方法或变量,会......
  • luogu P3232 [HNOI2013]游走 (期望, 高斯消元)
    https://www.luogu.com.cn/problem/P3232思路:算出每条边的期望访问次数,将期望访问次数多的赋予小的编号。一条边的期望访问次数=访问点u的期望/u的度+访问点v的期望......
  • GAN初步-生成1010格式规律的向量
    GAN初步-生成1010格式规律的向量构建和训练GAN的推荐步骤:(1)从真实数据集预览数据;(2)测试鉴别器至少具备从随机噪声中区分真实数据的能力;(3)测试未经训练的生成器能否创建......
  • 20201306吴龙灿第四章学习笔记
    知识点归纳前言学习了解并发编程的概念,理解并行计算的概念和重要性;掌握线程的原理和其对于进程的优势。通过学习Pthread线程操作,了解如何使用线程进行并发编程;理解死锁问......
  • #yyds干货盘点# 面试必刷TOP101:字符串变形
    1.简述:描述对于一个长度为n 字符串,我们需要对它做一些变形。首先这个字符串中包含着一些空格,就像"HelloWorld"一样,然后我们要做的是把这个字符串中由空格隔开的单词反序,......
  • #yyds干货盘点# 面试必刷TOP101:最长公共前缀
    1.简述:描述给你一个大小为n 的字符串数组strs,其中包含n个字符串,编写一个函数来查找字符串数组中的最长公共前缀,返回这个公共前缀。数据范围: , 进阶:空间复杂度 ,时间......
  • 江南信息学第六周练习20221014
    1001:给定一个字符,用它构造一个对角线长3个字符,倾斜放置的菱形1002:一只大象口渴了,要喝20升水才能解渴,但现在只有一个深h厘米,底面半径为r厘米的小圆桶(h和r都是整数)。问大......