【动态规划】小S的货船租赁冒险

news2024/12/27 7:45:05

文章目录

        • 一、问题描述
          • 输入格式
          • 输出格式
        • 问题背景
        • 二、动态规划思想
        • 三、代码实现细节
          • 初始化二维数组
          • 遍历每种货船
          • 遍历预算并更新状态
          • 提前剪枝优化
        • 四、代码实现
        • 算法复杂度分析
        • 优化思路

一、问题描述

李华在码头租货船,有 Q 种货船可以租赁。第 i 种货船的数量为 m[i], 租赁价格为 v[i],载货量为 w[i]。求预算为 V 的情况下,李华租的货船载货量总和 W 最大为多少?

输入格式

共两行。

第 1 行为两个用空格分隔开的整数:Q(1 <= Q <= 50)V(1 <= V <= 4000)Q 表示货船种类数,V 表示李华的预算。

第 2 行到第 Q + 1 行是 Q 种货船的详细信息。第 i + 1(1 <= i <= Q) 行有三个用空格分隔开的整数:m[i](1 <= m[i] <= 1000)v[i](1 <= v[i] <= 100)w[i](1 <= w[i] <= 100) ,表示第 i 种货船的数量、租赁价格和载货量。

输出格式

输出李华预算为 V 的情况下,货船载货量总和 W 的最大值。

问题背景

李华想通过预算限制,在码头租用货船以最大化货物载量。每种货船有数量限制、租赁成本和载货量。目的是找到一种最优租船方案,使总预算不超过 ( V ),并让货物载量达到最大。这是典型的多重背包问题

二、动态规划思想

动态规划的核心是将问题分解为子问题,利用子问题的最优解构建原问题的最优解。具体到本问题,可以通过如下步骤构造解法:

  1. 状态定义
    定义 dp[i][j] 表示前 ( i ) 种货船在预算为 ( j ) 时的最大载货量。

    • ( i ) 代表当前考虑到的货船种类数。
    • ( j ) 代表当前可用的预算。
  2. 状态转移

    • 不选择当前第 ( i ) 种货船时,最大载货量为前 ( i-1 ) 种货船在预算为 ( j ) 时的最大载货量,即 dp[i][j] = dp[i-1][j]

    • 如果选择第 ( i ) 种货船,则需要从预算 ( j ) 中扣除相应的租赁成本,同时增加载货量。可以选择 ( k ) 艘船,
      在这里插入图片描述

    • 遍历 ( k ) 直到预算或货船数量的限制。

  3. 边界条件

    • 当没有货船或预算为 0 时,最大载货量为 0,即 dp[0][j] = 0dp[i][0] = 0
  4. 结果输出

    • 最终答案为 dp[Q][V],表示考虑所有 ( Q ) 种货船并且预算为 ( V ) 时的最大载货量。
三、代码实现细节
初始化二维数组

二维数组 dp 用于存储中间状态结果,其大小为 (Q+1)* (V+1) 。所有初始值均为 0,表示当预算不足或没有船可用时,最大载货量为 0。

int[][] dp = new int[Q + 1][V + 1];
遍历每种货船

外层循环遍历所有货船。对于每种货船,获取其数量 ( m )、租赁成本 ( v ) 和载货量 ( w )。

for (int i = 1; i <= Q; i++) {
    int m = ships.get(i - 1).get(0); // 数量
    int v = ships.get(i - 1).get(1); // 成本
    int w = ships.get(i - 1).get(2); // 载货量
遍历预算并更新状态

对于当前货船 ( i ),内层循环遍历预算 ( j ) 从 ( 0 ) 到 ( V ),计算每种选择下的最优解。

  • 不选择当前货船:

    dp[i][j] = dp[i - 1][j];
    
  • 遍历选择 1 到 ( m ) 艘货船:

    for (int k = 1; k <= m; k++) {
        if (j >= k * v) {
            dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - k * v] + k * w);
        } else {
            break; // 提前退出循环
        }
    }
    
提前剪枝优化

当预算 ( j ) 不足以选择 ( k ) 艘船时,直接退出循环,避免无效计算。

四、代码实现
import java.util.ArrayList;
import java.util.List;

public class Main {
    public static int solution(int Q, int V, List<List<Integer>> ships) {
        // 初始化二维数组 dp,大小为 (Q + 1) x (V + 1)
        int[][] dp = new int[Q + 1][V + 1];

        // 遍历每种货船
        for (int i = 1; i <= Q; i++) {
            int m = ships.get(i - 1).get(0); // 当前货船的数量
            int v = ships.get(i - 1).get(1); // 当前货船的租赁成本
            int w = ships.get(i - 1).get(2); // 当前货船的载货量

            // 遍历预算,从 0 到 V
            for (int j = 0; j <= V; j++) {
                // 不选择第 i 种货船
                dp[i][j] = dp[i - 1][j];

                // 遍历选择 k 艘当前货船
                for (int k = 1; k <= m; k++) {
                    if (j >= k * v) {
                        dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - k * v] + k * w);
                    } else {
                        break; // 如果预算不足,提前退出循环
                    }
                }
            }
        }

        // 返回在预算 V 内的最大载货量
        return dp[Q][V];
    }

    public static void main(String[] args) {
        // 测试用例
        List<List<Integer>> ships = new ArrayList<>();
        ships.add(List.of(2, 3, 2));
        ships.add(List.of(3, 2, 10));

        List<List<Integer>> ships2 = new ArrayList<>();
        ships2.add(List.of(30, 141, 47));
        ships2.add(List.of(9, 258, 12));
        ships2.add(List.of(81, 149, 13));
        ships2.add(List.of(91, 236, 6));
        ships2.add(List.of(27, 163, 74));
        ships2.add(List.of(34, 13, 58));
        ships2.add(List.of(61, 162, 1));
        ships2.add(List.of(80, 238, 29));
        ships2.add(List.of(36, 264, 28));
        ships2.add(List.of(36, 250, 2));
        ships2.add(List.of(70, 214, 31));
        ships2.add(List.of(39, 116, 39));
        ships2.add(List.of(83, 287, 4));
        ships2.add(List.of(61, 269, 94));
        ships2.add(List.of(23, 187, 46));
        ships2.add(List.of(78, 33, 29));
        ships2.add(List.of(46, 151, 2));
        ships2.add(List.of(71, 249, 1));
        ships2.add(List.of(67, 76, 85));
        ships2.add(List.of(72, 239, 17));
        ships2.add(List.of(61, 256, 49));
        ships2.add(List.of(48, 216, 73));
        ships2.add(List.of(39, 49, 74));

        System.out.println(solution(2, 10, ships) == 32);
        System.out.println(solution(23, 400, ships2) == 1740);
    }
}
算法复杂度分析
  1. 时间复杂度

    • 外层循环遍历 Q 种货船。
    • 每种货船最多需要遍历预算 ( V ),并对 ( m[i] ) 的数量进行内部循环。
    • 总时间复杂度为 ( O(Q * V * m ),其中 ( m ) 为每种货船的平均数量。
  2. 空间复杂度

    • 使用二维数组 dp,空间复杂度为 O(Q * V) 。
优化思路
  1. 空间优化

    • 使用一维数组滚动优化,将 dp[i][j] 转换为 dp[j],仅保留上一层的状态,减少空间复杂度到 ( O(V) )。
  2. 二进制拆分优化

    • 使用二进制拆分将多重背包问题转化为若干个 0-1 背包问题,减少内部循环次数。

间复杂度为 O(Q * V) 。


博客主页: 总是学不会.

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

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

相关文章

基于 MVC 架构的 SpringBoot 高校行政事务管理系统:设计优化与实现验证

摘 要 身处网络时代&#xff0c;随着网络系统体系发展的不断成熟和完善&#xff0c;人们的生活也随之发生了很大的变化&#xff0c;人们在追求较高物质生活的同时&#xff0c;也在想着如何使自身的精神内涵得到提升&#xff0c;而读书就是人们获得精神享受非常重要的途径。为了…

【k8s 深入学习之 event 聚合】event count累记聚合(采用 Patch),Message 聚合形成聚合 event(采用Create)

参考 15.深入k8s:Event事件处理及其源码分析 - luozhiyun - 博客园event 模块总览 EventRecorder:是事件生成者,k8s组件通过调用它的方法来生成事件;EventBroadcaster:事件广播器,负责消费EventRecorder产生的事件,然后分发给broadcasterWatcher;broadcasterWatcher:用…

HTML5动漫主题网站——天空之城 10页 html+css+设计报告成品项目模版

&#x1f4c2;文章目录 一、&#x1f4d4;网站题目 二、✍️网站描述 三、&#x1f4da;网站介绍 四、&#x1f310;网站演示 五、⚙️网站代码 &#x1f9f1;HTML结构代码 &#x1f492;CSS样式代码 六、&#x1f527;完整源码下载 七、&#x1f4e3;更多 一、&#…

day2 美化后的登录

import sysfrom PyQt6.QtGui import QIcon, QPixmap from PyQt6.QtWidgets import QApplication, QWidget, QLabel from PyQt6 import uicclass MyWidget(QWidget):def __init__(self):super().__init__()self.setWindowTitle("猫咪乐园")uiuic.loadUi("./untit…

uniapp 自定义导航栏增加首页按钮,仿微信小程序操作胶囊

实现效果如图 抽成组件navbar.vue&#xff0c;放入分包 <template><view class"header-nav-box":style"{height:Props.imgShow?:statusBarHeightpx,background:Props.imgShow?:Props.bgColor||#ffffff;}"><!-- 是否使用图片背景 false…

Android KEY的哪些事儿

目录 一、APK应用签名 1、什么是APK应用签名&#xff1f; 1.1 目的和作用&#xff1f; 1.2 长什么样子&#xff1f; 2、APK应用签名使用流程 步骤一&#xff1a;如何生成APK应用签名文件&#xff1f; 步骤二&#xff1a;如何集成APK应用签名文件&#xff1f; 步骤三&am…

Docker中安装GeoServer

一、准备工作 #创建数据持久化目录 mkdir -p /usr/local/application/geoserver/data_dir#授权 chmod 777 -R /usr/local/application/ 这一步是为了在容器外部管理GeoServer的数据&#xff0c;使得数据能够持久化存储。 二、拉取GeoServer镜像 从Docker Hub拉取GeoServer的…

Create Stunning Word Clouds with Ease!

Looking to craft breathtaking word clouds? WordCloudStudio is your go-to solution! Whether you’re a marketer, educator, designer, or simply someone who loves visualizing data, this app has everything you need. Download now: https://apps.apple.com/app/wor…

【JavaEE初阶】落霞与孤鹜齐飞,秋水共长天一色 - (重点)线程

本篇博客给大家带来的是线程的知识点, 由于时间有限, 分三天来写, 本篇为线程第二篇. &#x1f40e;文章专栏: JavaEE初阶 &#x1f680;若有问题 评论区见 ❤欢迎大家点赞 评论 收藏 分享 如果你不知道分享给谁,那就分享给薯条. 你们的支持是我不断创作的动力 . 王子,公主请阅…

java_判断语句——acwing

题目一&#xff1a;倍数 665. 倍数 - AcWing题库 代码 import java.util.Scanner;public class Main{public static void main(String[] args) {Scanner sc new Scanner(System.in);int a sc.nextInt(), b sc.nextInt();if(a%b0 || b%a0) System.out.printf("Sao Mu…

深度解析棋牌游戏开发:从搭建到运营的全流程实战分享

作为从事游戏开发十五年的技术老兵&#xff0c;经历了国内游戏市场从端游到手游的全流程变迁。市面上大多数棋牌产品&#xff0c;无论是传统房卡模式还是创新竞技玩法&#xff0c;自己曾经都参与设计和研发过。今天&#xff0c;我将结合多年的实战经验&#xff0c;分享棋牌游戏…

mfc110u.dll是什么意思,mfc110u.dll丢失解决方法大全详解

mfc110u.dll是Microsoft Foundation Classes (MFC)库的一个特定版本&#xff08;版本11.0&#xff09;的Unicode动态链接库文件。MFC是Microsoft为C开发者设计的一个应用程序框架&#xff0c;主要用于简化Windows应用程序的开发工作。这个框架封装了很多Windows API函数&#x…

【C++跬步积累】—— 继承

&#x1f30f;博客主页&#xff1a;PH_modest的博客主页 &#x1f6a9;当前专栏&#xff1a;C跬步积累 &#x1f48c;其他专栏&#xff1a; &#x1f534; 每日一题 &#x1f7e1; Linux跬步积累 &#x1f7e2; C语言跬步积累 &#x1f308;座右铭&#xff1a;广积粮&#xff0…

爬虫专栏第二篇:Requests 库实战:从基础 GET 到 POST 登录全攻略

简介&#xff1a;本文聚焦 Requests 库的强大功能与应用实战。首先介绍其安装步骤及版本选择要点&#xff0c;随后深入讲解 GET 请求&#xff0c;以百度页面为例&#xff0c;展示如何发起基本 GET 请求、巧妙添加 headers 与参数以精准搜索&#xff0c;以及正确设置 encoding 避…

计算机网络:IP协议详细讲解

目录 前言 一、IP网段划分 二、IP报头 三、解决IP地址不足-->NAT技术 前言 在之前&#xff0c;我们学习了传输层中的TCP和UDP&#xff0c;重点是TCP协议&#xff0c;他帮我们解决具体到主机的哪个应用&#xff08;端口&#xff09;、传输的可靠&#xff08;序列号、校验和…

Proteus8.17下载安装教程

Proteus是一款嵌入式系统仿真开发软件&#xff0c;实现了从原理图设计、单片机编程、系统仿真到PCB设计&#xff0c;真正实现了从概念到产品的完整设计&#xff0c;其处理器模型支持8051、HC11、PIC10/12/16/18/24/30/DsPIC33、AVR、ARM、8086和MSP430等&#xff0c;能够帮助用…

C++设计模式(装饰模式)

一、介绍 1.动机 在某些情况下我们可能会“过度地使用继承来扩展对象的功能”&#xff0c;由于继承为类型引入的静态特质&#xff0c;使得这种扩展方式缺乏灵活性&#xff1b;并且随着子类的增多&#xff08;扩展功能的增多&#xff09;&#xff0c;各种子类的组合&#xff0…

【VMware】Ubuntu 虚拟机硬盘扩容教程(Ubuntu 22.04)

引言 想装个 Anaconda&#xff0c;发现 Ubuntu 硬盘空间不足。 步骤 虚拟机关机 编辑虚拟机设置 扩展硬盘容量 虚拟机开机 安装 gparted sudo apt install gparted启动 gparted sudo gparted右键sda3&#xff0c;调整分区大小 新大小拉满 应用全部操作 调整完成

03-12、SpringCloud Alibaba第十二章,升级篇,服务注册与配置中心Nacos

SpringCloud Alibaba第十二章&#xff0c;升级篇&#xff0c;服务注册与配置中心Nacos 一、为什么SpringCloud Alibaba 1、为什么 有了spring cloud这个微服务的框架&#xff0c;为什么又要使用spring cloud alibaba这个框架了&#xff1f;最重要的原因在于spring cloud中的…

java网络通信(三):TCP通信、实现客户端-服务端消息通信

目录 1、什么是 TCP协议&#xff1f; 2、代码实现TCP协议的一发一收 2.1、客户端 2.2、服务端 2.3 结果演示 3、代码实现TCP协议的多发多收 3.1 客户端 3.2 服务端 3.3 结果演示 简介&#xff1a;本文章主要是演示如何用java代码以及TCP协议实现网络通信&#xff0c;实…