算法设计基础——综合

算法设计基础中最基础的几种算法:分治法、减治法、贪心法、动态规划法、回溯法基本都掌握后,我们现在可以对这些算法做整体的比较,本次实验使用蛮力法、动态规划法、回溯法来求解0/1背包问题,来比较各个算法的优劣。

1. 蛮力法

问题描述:

有n个物品待装入背包,给出各个物品的价值和重量以及背包的容量,需要求出一个最佳的方案使得装入背包的物品总价值最高。此问题为子集问题,总共的方案数有2^n种,这些方案可以用一串二进制序列表示:000、001、010等,这样要求出一个个的方案只需要求出一系列的二进制数即可,然后再对这些方案一个个试探判断是否符号条件,最后找出最佳方案。

解决办法:

此题为子集问题,考虑子集的形式,使用01表示是否集合中的某个元素,这样子集的序列为{0,0,0}、{0,0,1}等,这些序列可以看做二进制的数,二进制数0到2^n-1,这些二进制序列即是集合的子集,这样只要求出二进制0到2^n-1即可求得所有子集序列。由于转换的二进制需要按位存放在数组中,可以直接把十进制数看做二进制数,循环对2取mod再除以2,得到每一位的数字,这些即构成了一串序列。通过对这些序列一一试探得到可能解,再从这些可能解中得到最优解。

算法描述:

算法:0/1背包问题蛮力法knapsackByBF

输入:n个物品的价值和重量、背包的容量

输出:最佳方案

过程:

  1. 定义变量bestValue存储最大价值并初始化为最小值
  2. 定义二维数组x[2^n][n]存储所有方案
  3. 定义i循环变量i并初始化为零,i从0到2^n-1,重复执行如下操作:
    1. 定义变量temp并赋值为i
    2. 定义循环变量j并初始化为0,j从0到n-1,重复执行如下操作:
      1. X[i][j]取temp个位的值(二进制)
      2. 判断该物品是否能装入背包,计算当前已经装入背包的物品的重量与价值,不能装入则置x[i][j]为0
      3. 更新最大值
      4. j++;
    3. i++;
  4. 返回最佳方案

对于一个简单的测试数据:

        int[] weight1 = {7, 3, 4, 5};int[] value1 = {42, 12, 40, 35};int capacity = 15;

计算流程如下图:

计算每一种可能解的结果,在所有解中寻找最优解。

时间复杂度计算:所要找出的方案数为2^n种,依次试探每一种方案,每一种方案的处理时间复杂度为O(1),总时间复杂度为O(2^n)。

算法实现:

public static int knapsackByBF(int[] weight, int[] value, int n, intcapacity){int i, j;int temp;       //临时存储各位的值int tempWeight;int bestValue = Integer.MIN_VALUE;      //最大价值int index = -1;      //最大价值的方案下标//首先使用蛮力法求出集合的所有子集for(i = 0; i < Math.pow(2, n); i++){    //一共2^n个子集tempWeight = 0;temp = i;for (j = 0; j < n; j ++){//temp = i % 2;           //取末位的值x[i][j] = temp % 2;     //将该数的所有位按二进制存放进数组,这个二进制序列即位集合的一个子集if(tempWeight + x[i][j] * weight[j] <= capacity) {     //若剩余容量足够则装入背包tempWeight += x[i][j] * weight[j];tValue[i] += x[i][j] * value[j];}else{x[i][j] = 0;        //无法装入则为0break;              //此物品无法装入,后面的物品也不能装入,直接退出循环}temp /= 2;      //继续存入下一位数字}if(tValue[i] > bestValue) {       //更新最大值bestValue = tValue[i];index = i;}}return index;
}

测试数据:

测试结果:

2. 动态规划法

问题描述:

有n个物品待装入背包,给出各个物品的价值和重量以及背包的容量,需要求出一个最佳的方案使得装入背包的物品总价值最高,使用动态规划法实现。考虑规划过程,i个物品j容量的背包的最大价值为不装入第i个物品和装入第i个物品两种选择中价值最大的一种。可采用填表法,依次将各种情况填写出来,直到i=n,j=capacity(n为物品数,capacity为背包容量)。

解决办法:

采用填表法实现,需要得到的是一个n个物品,capacity背包容量的最佳方案,把原问题分解多个i个物品,j背包容量的子问题,i从0到n,j从0到capacity,对每一个子问题进行求解,由子问题的解推出原问题的解。每个子问题的求解过程如下:背包容量足够时当前子问题的解为装入这个物品和不装入这个物品两种方案中价值较大者,背包容量不足时子问题的解为不装入这个物品。

对于数据:

        int[] weight1 = {7, 3, 4, 5};int[] value1 = {42, 12, 40, 35};int capacity = 15;

计算流程如下图:

对每一行没一列进行填表,后面的结果根据前面得到的结果推出,依次计算到i=n,j=capacity为止。

算法描述:

算法:0/1背包问题蛮力法knapsackByBF

输入:n个物品的价值value[]和重量weight[]、背包的容量capacity

输出:最佳方案

过程:

  1. 定义二维数组v[n][capacity]存储所有子问题
  2. 填写第一行,v[0][j]=0,j取0到capacity
  3. 填写第一列,v[i][0]=0,i取0到n
  4. 填写每一行:
    1. 若j<weight[i],该物品重量大于背包容量,无法放入,v[i][j]=v[i-1][j],
    2. 若j>=weight[i],该物品可以放入,v[i][j]取v[i-1][j]和v[i-1][j-weight[i]+value[i]二者的较大者
  5. 返回v[n][capacity];

算法实现:

public static int knapsackByDP(int[] weight, int[] value, int n, intcapacity){int i, j;int[][] v = new int[100][100];for(j = 0; j <= capacity; j++)         //填写第一行v[0][j] = 0;for(i = 0; i <= n; i++)                 //填写第一列v[i][0] = 0;for(i = 1; i <= n; i++)                 //填写其他行(i为物品)for(j = 1; j <= capacity; j++){      //j为背包剩余容量if(j < weight[i])               //背包容量不足,不放人这个物品v[i][j] = v[i - 1][j];elsev[i][j] = Math.max(v[i-1][j], v[i-1][j-weight[i]] + value[i]);}i = n;j = capacity;for(; i > 0; i--) {       //回溯寻找求解方案if (v[i][j] > v[i - 1][j]) {    //v[i][j]大于v[i-1][j]则说明该物品被装入xl[i] = 1;j -= weight[i];}elsexl[i] = 0;}return v[n][capacity];
}

测试数据:

 

测试结果:

3. 回溯法

问题描述:

有n个物品待装入背包,给出各个物品的价值和重量以及背包的容量,需要求出一个最佳的方案使得装入背包的物品总价值最高,使用回溯法实现。每一个物品都有装入和不装入两种选择,依次对这两种选择进行试探,直到试探到最后一个元素或者超出背包容量。

解决办法:

每一个物品都有装入和不装入两种选择,依次对这两种选择进行试探,直到试探到最后一个元素或者超出背包容量。

算法描述:

算法:0/1背包问题回溯法knapsackByBacktrack

输入:n个物品的价值value[]和重量weight[]、背包的容量capacity

输出:最佳方案

过程:

  1. 如果所有物品均探测完毕或装入背包的物品重量超出背包容量:
    1. 如果重量超过范围,算法结束;
    2. 否则当前已探索出一个方案,进行更新最大值操作;
  2. 探索不装入该物品的方案
  3. 探索装入该物品的方案

时间复杂度计算:总共有2^n种方案,回溯法需要依次对所有方案进行试探,每种方案试探的时间复杂度为O(1),则总时间复杂度为O(2^n)。

算法实现:

public static void knapsackByBacktrack(int count, int weightSum, int 
capacity, int valueSum){if(count == n || weightSum >= capacity){ //所有物品都走完或超出背包重量则路线寻找完毕if(weightSum > capacity)return;if(valueSum > bestValueb)bestValueb = valueSum;//visited[pathCount] = valueSum;     //存储该方案的总价值以便后续判断pathCount++;System.arraycopy(path[pathCount - 1], 0, path[pathCount], 0, count);return;}path[pathCount][count] = 0;knapsackByBacktrack(count + 1, weightSum, capacity, valueSum);path[pathCount][count] = 1;knapsackByBacktrack(count + 1, weightSum+weight[count],capacity, valueSum + value[count]);}

测试数据:

测试结果:

4. 总结

蛮力法是最粗暴简单的一种算法,它的基本思想就是寻找所有的可能解,将所有可能的解都计算出来,根据题目的要求寻找满足条件的解,或者找出最优解。蛮力法一般的实现方法是循环遍历,根据题目的要求,遍历各种情况,对每种情况进行计算,最后得出可行解或者找出最优解。蛮力法因为其简单粗暴的特点,比较适合初学者入门,使用蛮力法非常容易实现,而且也很容易计算蛮力法的时间复杂度,此外,使用蛮力法基本不需要什么限制,因此基本对所有问题都能求解。但是也正是因为蛮力法简单粗暴的特点,它可以说是完全没有对问题简化,计算复杂度非常的高,基本就是所有算法中计算复杂度最高的一种算法,也因此其他算法经常会与蛮力法进行比较。

动态规划法与分治法有些类似,动态规划法是将问题划分为重叠的多个子问题,然后根据题目给出一个动态规划函数,这是动态规划法的关键,动态规划函数是子问题满足的递推关系式,在计算每个子问题的时候,都是使用动态规划函数从前面计算得到的子问题的解推导出本身的解。因此动态规划法再计算时会将前面计算的结果保存,后面的子问题在计算时可以直接使用前面的计算结果,不用重复计算,因此动态规划法避免了大量的计算。动态规划法是根据子问题的最优解求出的原问题的最优解,这个最优解是全局最优的,因为它是根据所有子问题一个个推导出来的。对于能够给出动态规划函数的问题,动态规划法都能够求解出最优解,对于多阶段最优化问题,动态规划法是非常适合的。

回溯法是基于深度优先搜索原理的一种搜索可能解的方法,它的搜索过程是深度优先搜索,也就是它会优先从一个结点的一条分支一直走下去,知道该分支路走不通了或者不满足约束条件才会停下,再回溯到上一个结点,从上一个结点的另一条分支继续向下一直探索。回溯法看上去和蛮力法很像,都是暴力探索可能的解,但回溯法与蛮力法最大的不同在于,回溯法不会探索完所有的解,它会根据一个约束条件判断当前结点的一条分支是否可行,如果不可行,回溯法会立即回溯,寻找另一个可能的解。不过回溯法的计算复杂度仍然是比较高的,通常比蛮力法也差不了多少,只有在某些问题上比较适合,比如迷宫寻找一条可能的通路,但在求解最优解的问题上,回溯法的性能就非常差了,因为它要计算每一个可能解,从所有可能解中找出最优解。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/228007.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

代码随想录27期|Python|Day16|二叉树|104.二叉树的最大深度|111.二叉树的最小深度|222.完全二叉树的节点个数

二叉树专题&#xff0c;重点掌握后续的递归和中间节点的处理。 104. 二叉树的最大深度 - 力扣&#xff08;LeetCode&#xff09; 本题在前一章已经解决了层序遍历的解法&#xff0c;现在来聊一下递归法。 首先需要明确两个概念&#xff1a;深度和高度。&#xff08;注意&…

抠图软件哪个好用?什么软件可以抠图换背景?

抠图软件哪个好用&#xff1f;在图片处理中&#xff0c;抠图换背景是一项常见的操作。很多新手可能会对此感到困惑&#xff0c;不知道应该使用什么软件来进行抠图换景。实际上&#xff0c;现在市面上有很多图片处理软件都具备抠图换背景的功能&#xff0c;每款软件都有其优缺点…

LVS负载均衡群集部署 DR模式

目录 DR模式直接路由 LVS-DR工作原理 LVS-DR 数据包流向分析 DR 模式的特点 DR模式 LVS负载均衡群集部署 DR模式直接路由 Direct Routing&#xff0c;简称DR模式&#xff0c;采用半开放式的网络结构&#xff0c;与TUN模式的结构类似&#xff0c;但各节点并不是分散在各地…

c语言链表的基本操作

在C语言中&#xff0c;链表是一种常见的数据结构&#xff0c;它由一系列节点组成&#xff0c;每个节点包含一个数据元素和一个指向下一个节点的指针。链表的基本操作包括创建、插入、删除和遍历等。 下面是一个简单的链表节点结构体定义&#xff1a; struct Node { int da…

Python实现员工管理系统(Django页面版 ) 六

本篇博客主要实现用户账号管理&#xff0c;这与之前的账号管理不同&#xff0c;之前的账号管理你可以理解为公司在外面买的一些手机号然后需要发放给员工做内部使用&#xff0c;而本篇博客的用户账号管理主要是为了后续的登录网页实现&#xff0c;那么我们开始今天的项目实现吧…

2. 套圈(分治)

题目 Have you ever played quoit in a playground? Quoit is a game in which flat rings are pitched at some toys, with all the toys encircled awarded. In the field of Cyberground, the position of each toy is fixed, and the ring is carefully designed so it c…

搭建消息时光机:深入探究RabbitMQ_recent_history_exchange在Spring Boot中的应用【RabbitMQ实战 二】

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 搭建消息时光机&#xff1a;深入探究RabbitMQ_recent_history_exchange在Spring Boot中的应用 引言前言第一&#xff1a;开启插件支持第二&#xff1a;springboot整合第三&#xff1a;效果展示交换机属…

locust 压测 websocket

* 安装 python 3.8 https://www.python.org/ py --version * 安装 locust pip install locust2.5.1 -i http://pypi.douban.com/simple/ pip install locust2.5.1 -i https://pypi.mirrors.ustc.edu.cn/simple/ locust -V 备注&#xff1a;-i 是切换下载源 * 安装依赖 pip ins…

Electron框架:构建跨平台桌面应用的终极解决方案

文章目录 一、Electron框架简介二、Electron框架的优势1. 开发效率高2. 跨平台性能好3. 易于维护4. 强大的原生能力 三、如何使用Electron框架快速开发跨平台桌面应用1. 安装Electron2. 创建项目文件夹3. 编写主进程代码4. 编写界面代码5. 运行应用 《Electron入门与实战》编辑…

《软件方法》2023版1.1利润=需求-设计1.2 ABCD工作流

DDD领域驱动设计批评文集 做强化自测题获得“软件方法建模师”称号 《软件方法》各章合集 第1章 建模和UML 牵着你走进傍晚的风里&#xff0c;看见万家灯火下面平凡的秘密。 《情歌唱晚》&#xff1b;词&#xff1a;黄群&#xff0c;曲&#xff1a;黄群&#xff0c;唱&#…

word文档实现“目录索引中标题加粗、前导符(...)和页码不加粗”效果

文章目录 1 展示论文模板需要呈现的效果2 所遇到的问题2.1 情形1&#xff1a;当更新整个目录后&#xff0c;目录中的所有文字都不加粗2.2 情形2&#xff1a;无法单独选中文字部分&#xff0c;如果相对文字部分加粗&#xff0c;则前导符和页码也会同时加粗 3 解决步骤3.1 步骤1&…

CIDR(无类域间路由)与VLSM(可变长度子网掩码)的区别

CIDR和VLSM的介绍 CIDR CIDR&#xff08;Classless Inter-Domain Routing&#xff0c;无类域间路由&#xff09;是一种用于对互联网协议&#xff08;IP&#xff09;地址进行聚合和分配的标准。CIDR的引入旨在解决IPv4地址空间的不足和低效分配的问题。在传统的IP地址规划中&a…

关键点检测之修改labelme标注的json中类别名

import json import os import shutil#source_dir表示数据扩增之后的文件夹路径&#xff0c;此时标注的是多分类的标签 #new_dir表示转化之后得到的二分类文件夹def to2class():#json存放路径source_dir r1#json保存路径new_dir r1for i in os.listdir(source_dir):if i.ends…

文本聚类——文本相似度(聚类算法基本概念)

一、文本相似度 1. 度量指标&#xff1a; 两个文本对象之间的相似度两个文本集合之间的相似度文本对象与集合之间的相似度 2. 样本间的相似度 基于距离的度量&#xff1a; 欧氏距离 曼哈顿距离 切比雪夫距离 闵可夫斯基距离 马氏距离 杰卡德距离 基于夹角余弦的度量 公式…

银行数字化转型导师坚鹏:银行数字化转型正在重塑您的工作

您好&#xff0c;我是银行数字化转型导师坚鹏。坚持知行果合一&#xff0c;赋能数字化转型&#xff01;非常荣幸和您分享关于银行数字化转型如何影响老百姓工作的一些思考。 您知道吗&#xff1f;银行数字化转型给您的工作方式带来新变化、新趋势、新潮流啦&#xff01;在这个…

一分钟解决:vscode卡在“设置SSH主机:VS Code-正在本地下载 VS Code 服务器”

问题&#xff1a;vscode之前可正常使用&#xff0c;更新之后&#xff0c;连接服务器卡住了。 解决&#xff1a;从CMD或者你的终端连接服务器&#xff0c;进入vscode-server目录下&#xff0c;删除一些文件夹就行&#xff0c;然后使用vscode重新链接&#xff0c;它会自动下载新…

系列七、函数

一、函数 1.1、概述 函数 是指一段可以直接被另一段程序调用的程序或代码。 也就意味着&#xff0c;这一段程序或代码MySQL中已经为我们提供好了&#xff0c;我们要做的就是在合适的业务场景调用对应的函数完成相应的业务需求即可。 1.2、分类 按照业务分类&#xff0c;MySQL中…

基于SSM的影视企业全渠道会员管理系统(有报告)。Javaee项目

演示视频&#xff1a; 基于SSM的影视企业全渠道会员管理系统&#xff08;有报告&#xff09;。Javaee项目 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c;通过Spring S…

Python将列表中的数据写入csv并正确解析出来

用Python做数据处理常常会将数据写到文件中进行保存&#xff0c;又或将保存在文件中的数据读出来进行使用。通过Python将列表中的数据写入到csv文件中很多人都会&#xff0c;可以通过Python直接写文件或借助pandas很方便的实现将列表中的数据写入到csv文件中&#xff0c;但是写…

计算机毕业设计 基于SpringBoot的物资管理信息系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…