动态规划算法(3)--0-1背包、石子合并、数字三角形

目录

一、0-1背包

1、概述

2、暴力枚举法

3、动态规划

二、石子合并问题

1、概述

2、动态规划

3、环形石子怎么办?

三、数字三角形问题

1、概述

2、递归

3、线性规划

 四、租用游艇问题 


一、0-1背包

1、概述

        0-1背包:给定多种物品和一个固定重量W的背包,每种物品有一个固定的重量w_i,价值v_i,现在要将物品装入背包,每种物品至多装入一个,使总重量不超过W,且总价值最大。

        约束条件和优化目标如下:

2、暴力枚举法

        暴力枚举法也是使用递归的方式,假设对前i个物品分析,总重量为c,当前总价值为P。那么存在递归条件:\begin{matrix} \quad \qquad p1=knapsack(i-1,c-w_i)\\ \quad p2=knapsack(i-1,c) \\ P=max(p1+v_i,p2) \end{matrix}

        另外当重量小于0时,总价值为-∞(代码中可以用-999替代),物品个数小于等于0,总价值为0。

        暴力枚举法依赖递归方式,没有减少子问题个数,所以根据递归树计算,复杂度为O(2^n)

        伪代码如下:

        代码实例: 

   //暴力枚举public static int violate_knapsack(int weight,int i,int weights[],int values[]){if (weight<0){return -9999; }if (i<=0)  {    return 0;}int p1=violate_knapsack(weight-weights[i],i-1,weights,values);   //选中i物品int p2=violate_knapsack(weight,i-1,weights,values);              //不选i物品int p=p1+values[i]>p2?p1+values[i]:p2;   return p;}

3、动态规划

        动态规划方法通过建立备忘录的方式,前i个物品,总重量为j的时刻永远依赖于前面的子结构。M数组为加入前i个物品后,总重量为j时的总价值,Rec数组表示是否有物品添加,若添加则为1,不添加则为0。

        原理:

参数:count代表总类别个数,weight代表背包重量,weights为物品重量,values为物品价值,name为物品名称。

(1)首先,M数组0行0列均为初值0,注意:行为重量,列为种类个数。

(2)按每行逐个值来填写M和Rec。如:前i个物品,总重量为j的情况下,即求M[i][j]时,如果该物品重量小于背包重量且在前i-1个物品,总重量为(j-当前物品重量)时的总重量+当前物品价值的总价值,大于前i-1个物品,总重量为j时的总价值时M填写较大的总价值,Rec=1。条件写为:weights[i-1]\leqslant j,values[i-1]+M[i-1][j-weights[i]]>M[i-1][j]

(3)由于调用j-当前物品重量时有可能为负数,所以保证最小值为0,设为minor。

(4)如果不满足(2)条件,则M[i][j]填上一行同列的M[i-1][j]值,即不选这个物品(索引为i-1)的总价值。Rec为0。

(5)最优解追寻:Rec数组倒序查找i取最大值,逐次减1,判断条件如果Rec数组为1,则从总重量weight中减少weights[i-1],输出name[i-1]物品,直到i取1。

//0-1背包问题
import java.util.ArrayList;
public class backage {public static void main(String []args){int values[]={24,2,9,10,9};int weights[]={10,3,4,5,4};int count=5;int weight=13;int M[][]=new int [count+1][weight+1];int Rec[][]=new int [count+1][weight+1];String name[]={"beer","cocacola","cookie","bread","milk"};//暴力求解System.out.println(violate_knapsack(weight,count-1,weights,values));  //建立M数组,Rec数组 knapsack(count,weight,M,Rec,weights,values);//M数组for(int i=0;i<count+1;i++){for(int j=0;j<weight+1;j++){System.out.print(M[i][j]+"\t");}System.out.println("");}//Rec数组for(int i=0;i<count+1;i++){for(int j=0;j<weight+1;j++){System.out.print(Rec[i][j]+"\t");}System.out.println("");}//输出最优解Print(count,weight,Rec,name,weights);} //动态规划public static void knapsack(int count,int weight,int M[][],int Rec[][],int weights[],int values[]){for(int i=0;i<count+1;i++)         //0行0列没有值参与M[i][0]=0;for(int j=0;j<weight+1;j++)M[0][j]=0;for(int i=1;i<count+1;i++)         //第一行的表示加入第一个物品,但是第一个物品在索引0处{for(int j=1;j<weight+1;j++){int minor;                 //minor的设计是防止j-weights出现小于0,有可能背包重量小于上一行物品的重量,从而小于背包质量,小于背包质量默认为0if(j-weights[i-1]<0)minor=0;elseminor=j-weights[i-1];if((weights[i-1]<=j) & (values[i-1]+M[i-1][minor]>M[i-1][j]))    //如果可以替换,M替换为新值,Rec更新为1{M[i][j]=values[i-1]+M[i-1][minor];Rec[i][j]=1;}else{M[i][j]=M[i-1][j];                                           //不能修改时,M用上一行同列值替换,Rec更新为0Rec[i][j]=0;}}}}//输出最优解public static void Print(int count,int weight,int Rec[][],String name[],int weights[]){for(int i=count;i>0;i--){if(Rec[i][weight]==1){System.out.println(name[i-1]);weight=weight-weights[i-1];}}}

M数组和Rec数组的写法:

二、石子合并问题

1、概述

        现在有n堆石子排成一排,要求将石子有次序地合并成一堆,规定每次只能选相邻的两堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分,设计一个算法将n堆石子合并成一堆的最小得分和最大得分。

        类比矩阵连乘问题求解,利用动态规划,设计m和s数组,最大值为m[1][n]。

2、动态规划

        动态规划转移方程(最小值):

        m[i][j]=\begin{Bmatrix} 0 \qquad \qquad \qquad \qquad \qquad \qquad \qquad \qquad \quad i=j\\ min(m[i][k]+m[k+1][j]+sum(i,j)) \quad i<j \end{Bmatrix}

        动态规划转移方程(最大值):

 m[i][j]=\begin{Bmatrix} 0 \qquad \qquad \qquad \qquad \qquad \qquad \qquad \qquad \quad i=j\\ max(m[i][k]+m[k+1][j]+sum(i,j)) \quad i<j \end{Bmatrix}

3、环形石子怎么办?

        如果题目要求石子堆围成一圈,其他要求不变,我们可以考虑将数组变为一个重复数组,由环形变为线性。如{1,2,3}则变为{1,2,3,1,2,3},n=2*n,然后考虑(j-i)>=arr_length时才满足原来的最多三个石子堆合并的问题。

        动态规划转移方程相同,只是多了一个退出循环的条件,同样的生成m数组,假设石子堆为{4,4,5,9},当前生成最小值m数组应该为下图示例:

        可以看到原先的m[1][n]为最小值,现在应该讨论min(m[i][n+i-1]) \quad 1\leqslant i\leqslant n,也就是四个数的最小值。

        代码示例:

//石子合并问题
public class stonemerge {public static void main(String[] args){int arr[]={4,4,5,9};int n=arr.length;int m[][]=new int[n+1][n+1]; int m_[][]=new int[n*2+1][n*2+1];int s[][]=new int[n+1][n+1]; minserge(arr,m_);System.out.println(trackmin(arr, m_));maxserge(arr, m_);System.out.println(trackmax(arr,m_));}//最小合并m数组 public static void minserge(int arr_[],int m[][]){int n=arr_.length*2;int arr[]=new int[n];add_arr(arr,arr_);for(int i=1;i<n;i++)m[i][i]=0;for (int r = 2; r <=n; r++) {for (int i = 1; i <= n - r + 1; i++) {               int j = i + r - 1;if((j-i)>=arr_.length)break;                m[i][j] = m[i + 1][j] + sum(i,j,arr);				             for (int k = i + 1; k < j; k++){int t = m[i][k] + m[k + 1][j] + sum(i,j,arr);if (t < m[i][j]) m[i][j] = t;}}}}//最大合并m数组public static void maxserge(int arr_[],int m[][]){int n=arr_.length*2;int arr[]=new int[n];add_arr(arr,arr_);for(int i=1;i<n;i++)m[i][i]=0;for (int r = 2; r <=n; r++) {for (int i = 1; i <= n - r + 1; i++) {               int j = i + r - 1;if((j-i)>=arr_.length)break;                m[i][j] = m[i + 1][j] + sum(i,j,arr);				             for (int k = i + 1; k < j; k++){int t = m[i][k] + m[k + 1][j] + sum(i,j,arr);if (t > m[i][j]) m[i][j] = t;}}}}//合并代价public static int sum(int i,int j, int arr[]){int tot=0;for(int m=i-1;m<=j-1;m++)tot+=arr[m];return tot;}//环形转线性数组生成public static void add_arr(int arr[],int arr_[]){for(int i=0;i<arr.length;i++){if(i<arr_.length)arr[i]=arr_[i];elsearr[i]=arr_[i-arr_.length];}}//最小值public static int trackmin(int arr[],int m[][]){int n=arr.length;int min=m[1][n];for(int i=2;i<=n;i++){if(m[i][n+i-1]<min)min=m[i][n+i-1];}return min;}//最大值public static int trackmax(int arr[],int m[][]){int n=arr.length;int max=m[1][n];for(int i=2;i<=n;i++){if(m[i][n+i-1]>max)max=m[i][n+i-1];}return max;}
}

三、数字三角形问题

1、概述

        给定一个由n行数字组成的数字三角形,设计算法,计算从三角形的顶至底的一条路径,每次必须下降一层,使该路径经过数字总和最大,如下图路线7-3-8-7-5,总和30。

2、递归

递归条件:

nums[x][y]+=max(trest(x+1,y),test(x+1,y+1)) \ x\neq n-1

               当x==n-1时为最底层数字,返回该数字。

//递归方法
public static int test(int x,int y,int nums[][]) {int n=nums.length;if(x == n-1) {return nums[x][y];}return (nums[x][y] + (test(x+1,y,nums) >= test(x+1,y+1,nums) ? test(x+1,y,nums) : test(x+1,y+1,nums)));}

3、线性规划

        状态转移方程与递归条件一样,只不过从倒数第二层向上叠加(参数i),每层的值改变为当前层到底层的最大值,变量k遍历某一层的每个数字,计算到底层的最大值并保存。

//动态规划
public static int max(int nums[][])
{for(int i=nums.length-2;i>=0;i--){int j=nums[i].length;for(int k=0;k<j;k++){nums[i][k]+=(nums[i+1][k]>=nums[i+1][k+1]?nums[i+1][k]:nums[i+1][k+1]);}}return nums[0][0];
}

 四、租用游艇问题

        游艇出租站租用游艇,并在下游的任何一个游艇出租站归还游艇,游艇出租站i到游艇出租站j之间的租金为r(i,j)(1<=i<j<=n),设计算法,计算出游艇出租站1到游艇出租站n的最少租金。

        输入的数字,第一行代表1到2的距离和1到3的距离,第二行代表2到3的距离。

//租用游艇问题
public class rentyacht {public static void main(String [] args){int cost[][]={{5,15},{7}};int n=cost.length;System.out.println(rentmin(cost,n));} public static int rentmin(int[][] cost, int n) {int[][] best = new int[n + 1][n + 1];for(int i = n - 1; i >= 1; i--) {best[i][n] = cost[i-1][n-1];for(int j = n - 1; j > i; j--) {best[i][n] = cost[i-1][j-1] + best[j][n]<best[i][n]?cost[i-1][j-1] + best[j][n]:best[i][n];}}return best[1][n];}
}

 

 

         

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

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

相关文章

ChatGPT,AIGC 数据库应用 Mysql 常见优化30例

使用ChatGPT,AIGC总结出Mysql的常见优化30例。 1. 建立合适的索引:在Mysql中,索引是重要的优化手段,可以提高查询效率。确保表的索引充分利用,可以减少查询所需的时间。如:create index idx_name on table_name(column_name); 2. 避免使用select * :尽可能指定要返回的…

HTML笔记

注释标签&#xff1a;<!-- --> 标题标签&#xff1a;&#xff08;作用范围依次递减&#xff09; <h1></h1> <h2></h2> <h3></h3> <h4></h4> <h5></h5> <h6></h6> 段落标签&#xff1a;<p&g…

抖音开放平台第三方代小程序开发,授权事件、消息与事件通知总结

大家好&#xff0c;我是小悟 关于抖音开放平台第三方代小程序开发的两个事件接收推送通知&#xff0c;是开放平台代小程序实现业务的重要功能。 授权事件推送和消息与事件推送类型都以Event的值判断。 授权事件推送通知 授权事件推送包括&#xff1a;推送票据、授权成功、授…

智能油烟机 优化烹饪体验

如果说空调是夏天最伟大的发明&#xff0c;那么油烟机则是健康厨房的伟大推进者。随着科技的发展&#xff0c;智能化的油烟机逐渐走进了人们的日常生活。每当我们在爆炒、油炸食物的时候&#xff0c;油烟总能呛得人眼睛痛、鼻子难受&#xff0c;传统的油烟机面前我们还需要手动…

vue3后台管理框架之路由配置

pnpm install vue-router 在src新建文件夹views和router 1.1基本 路由配置 :hash 路由模式 // 对外配置路由 import Login from @/views/login/index.vue import Home from @/views/home/index.vue import Error from @/views/404/index.vue export cons

JavaScript基础知识13——运算符:一元运算符,二元运算符

哈喽&#xff0c;大家好&#xff0c;我是雷工。 JavaScript的运算符可以根据所需表达式的个数&#xff0c;分为一元运算符、二元运算符、三元运算符。 一、一元运算符 1、一元运算符&#xff1a;只需要一个表达式就可以运算的运算符。 示例&#xff1a;正负号 一元运算符有两…

英语——歌曲篇——All Out Of Love

All Out Of Love [Air Supply失落的爱] 歌词 I’m lying alone with my head on the phone Thinking of you till it hurts I know you hurt too but what else can we do Tormented and torn apart I wish I could carry your smile in my heart For times when my life se…

自动驾驶学习笔记(五)——绕行距离调试

#Apollo开发者# 学习课程的传送门如下&#xff0c;当您也准备学习自动驾驶时&#xff0c;可以和我一同前往&#xff1a; 《自动驾驶新人之旅》免费课程—> 传送门 《2023星火培训【感知专项营】》免费课程—>传送门 文章目录 前言 调试内容 打开在线编辑器 打开pl…

基础算法:二分查找

目录 1. 二分查找2. 补充&#xff1a;二进制运算2.1 十进制与二进制的相互转换2.1.1 十进制转二进制2.1.2 二进制转十进制 2.2 机器数 真值2.3 原码 补码 反码2.4 二进制的加减乘除2.5 移位运算 1. 二分查找 思想&#xff1a; 有序数组&#xff0c;从中找值 实现&#xff1a;…

IDEA报Error:java:无效的源发行版13解决方式

出现问题原因&#xff1a;原本项目是spingboot2.0版本开发的&#xff0c;IDEA启动正常&#xff0c;后期新项目使用spingboot3.0&#xff0c;通过原来的IDEA版本及JDK1.8启动报上述错误&#xff0c;以下为版本文件 解决方式&#xff1a; 项目背景&#xff1a;项目已经上线&…

因为写保护,U盘会“假死”。如何在Windows 10上删除写保护

本文介绍如何从USB驱动器、SD卡或单个文件中删除写保护。说明适用于Windows 10、Windows 8和Windows 7。 如何使用锁定开关解除写保护 如果你的计算机告诉你介质受写保护&#xff0c;请在USB或SD卡上查找写保护开关&#xff08;也称为锁定开关&#xff09;。如果介质有此开关…

中断机制-通过volatile实现线程中断停止

4.1.4 大厂面试题中断机制考点 如何停止中断运行中的线程&#xff1f; 通过一个volatile变量实现 package com.nanjing.gulimall.zhouyimo.test;import java.util.concurrent.TimeUnit;/*** author zhou* version 1.0* date 2023/10/15 2:34 下午*/ public class InterruptD…

JS DataTable中导出PDF右侧列被截断的问题解决

JS DataTable中导出PDF右侧列被截断的问题解决 文章目录 JS DataTable中导出PDF右侧列被截断的问题解决一. 问题二. 解决办法三. 代码四. 参考资料 一. 问题 二. 解决办法 设置PDF大小和版型 orientation: landscape, pageSize: LEGAL,上述代码设置打印的PDF尺寸为LEGAL&…

深入理解 JVM(重点:双亲委派模型 + 垃圾回收算法)

一、什么是 JVM&#xff1f; JVM 是 Java Virtual Machine 的简称&#xff0c;意为 Java虚拟机。虚拟机是指通过软件模拟的具有完整硬件功能的、运行在一个完全隔离的环境中的完整计算机系统。可以认为 JVM 是一台被定制过的现实当中不存在的计算机&#xff0c;Java程序最终是…

Android---Android 是如何通过 Activity 进行交互的

相信对于 Android 工程师来说&#xff0c;startActivity 就像初恋一般。要求低&#xff0c;见效快&#xff0c;是每一个菜鸟 Android 工程师迈向高级 Android 工程师的必经阶段。经过这么多年的发展&#xff0c;startActivity 在 google 的调教下已经变得愈发成熟&#xff0c;对…

【Express】服务端渲染(模板引擎 EJS)

EJS&#xff08;Embedded JavaScript&#xff09;是一款流行的模板引擎&#xff0c;可以用于在Express中创建动态的HTML页面。它允许在HTML模板中嵌入JavaScript代码&#xff0c;并且能够生成基于数据的动态内容。 下面是一个详细的讲解和示例&#xff0c;演示如何在Express中…

Mac安装Kali保姆级教程

Mac安装Kali保姆级教程 其他安装教程&#xff1a;使用VMware安装系统Window、Linux&#xff08;kali&#xff09;、Mac操作系统 1 虚拟机安装VM Fusion 去官网下载VM Fusion 地址&#xff1a;https://customerconnect.vmware.com/en/evalcenter?pfusion-player-personal-13 …

网工记背配置命令(3)----POE配置示例

POE 供电就是通过以太网供电&#xff0c;这种方式仅凭借那根连接通信终端的网线就可完成为它们供电。POE提供的是-53V~0v 的直流电&#xff0c;供电距离最长可达 100m。PoE 款型的交换机的软件大包天然支持 POE&#xff0c;无需 license&#xff0c;通过执行 poe-enable 命令使…

Android 10.0 禁止弹出系统simlock的锁卡弹窗功能实现

1.前言 在10.0的系统开发中,在一款产品中,需要实现simlock锁卡功能,在系统实现锁卡功能以后,在开机的过程中,或者是在插入sim卡 后,当系统检测到是禁用的sim卡后,就会弹出simlock锁卡弹窗,要求输入puk 解锁密码,功能需求禁用这个弹窗,所以就需要看是 哪里弹的,禁用…

记一次生产大对象及GC时长优化经验

最近在做一次系统整体优化,发现系统存在GC时长过长及JVM内存溢出的问题,记录一下优化的过程 面试的时候我们都被问过如何处理生产问题&#xff0c;尤其是线上oom或者GC调优的问题更是必问&#xff0c;所以到底应该如何发现解决这些问题呢&#xff0c;用真实的场景实操&#xff…