有依赖的的动态规划问题

news2025/3/17 7:52:50

题目

在这里插入图片描述
在这里插入图片描述

题型分析

这是比较典型的动态规划的问题。动态规划是什么呢?本质上动态规划是对递归的优化。例如,兔子数列:f(x) = f(x - 1) + f(x -2), 我们知道 f 代表了计算公式,这里解放思想一下,如果 f 替换为数组,将每个 f(x) 的返回值返回,那么是不是就不用计算了,直接返回了,这样就节省了 CPU 递归和计算的时间,提高计算的效率,这样就对递归进行了优化。

public static fb(int input){
   if(input == 1){
      return 1 ;
   }
   if(input == 2){
      return 2 ;
   }
   return fb(input -1) + fb(input - 2);
}

改成动态规划:

public static fb(int input){
   int[] dp = new int[input + 1];
   dp[1] = 1 ;
   dp[2] = 2 ;
   for(int i = 3 ; i <= input ; i++){
     dp[i] = dp[i - 1] + dp[i - 2] ;
   }
   return dp[input] ;
}

斐波那契数列只是一个数列而已。只是我们可以从中总结出一些规律:

  1. 找到初始值。这就是递归的出口。
  2. 然后以初始值为起点,往后继续计算。这代表了各个递归调用。

说完斐波那契数列,我们可以把难度增加。经典的 0-1 背包问题。它题目往往是这样有两个一维数组,第一个代表了容量,第二个代表价值,给定一个 N 正整数值,N 值是背包能装的容量,数组的一个元素代表了一个物品,一个物品只能装一个,问背包能装下的最大价值是多少?
递归的算法:
定义 process(int i , int N , int[][] capacity , int[][] value) , 其中 i 代表 i ~ capacity.length 容量为 N 的情况下,返回最大的价值。
于是可以按两种情况处理。

  1. 不要 i 物品, 那么递归应该 process(i , N ) = process(i + 1 , N)
  2. 要 i 物品,那么递归应该 process(i , N) = value[i] + process(i + 1 , N - capacity[i])
  3. 然后取里面最大的那个。

有了上面的分析,递归可以写为:

    public static int process(int[] weight, int[] value, int startIdx, int bagWeight) {
        if (startIdx == weight.length - 1) {
            return (weight[startIdx] <= bagWeight ? value[startIdx] : 0);
        }
        if (bagWeight == 0) {
            return 0;
        }
        // 不将 startIdx 的物品放入背包
        int v1 = process(weight, value, startIdx + 1, bagWeight);
        int v2 = 0;
        if (bagWeight >= weight[startIdx]) {
            v2 = process(weight, value, startIdx + 1, bagWeight - weight[startIdx])
                    + value[startIdx];
        }

        return Math.max(v2, v1);
    }

同样的如果将 process 看成是数组,那么可以想象:

  1. 可以先计算出 dp[capacity.length -1 ][0 … N] 的初始中,代表的业务含义是当容量从 0 到 N 时的最大价值。
  2. 我们可以看出 i 的值是依赖于 i + 1 的值,所以 dp[capacity.length - 2 ][0 … N] 也可以计算出来,一次类推,数组的所有需要的值都可以计算出来。
  3. 最后返回的是 dp[0][N] 的值就可以了。

于是动态规划的版本如下所示:


    public static int processWithDp(int[] w , int[] v , int bag){
        int[][] dp = new int[w.length+1][bag+1];
        int p1 = 0 ;
        int p2 = 0 ;
        for(int index = w.length - 1 ; index >=0  ; index--){
            for(int rest = 0 ; rest <= bag ; rest++){
                 p1 = dp[index+1][rest];
                 p2 = 0 ;
                 if(rest >= w[index]){
                     p2 = dp[index+1][rest - w[index]] + v[index];
                 }
                 dp[index][rest] =  Math.max(p1 , p2);
            }

        }
        return dp[0][bag] ;
    }

最后说到这个题目,此题是在 0-1 背包的基础上增加了依赖。从题目中,可以知道附件不能离开主件独立存在,所以可以先以主件分组,A1{main , fj1 , fj2 } , A2{main , fj1 , fj2} … 在计算的时候,取下面的最大值。

  1. 不要 i 主件物品, A(i , N) = A(i +1 , N)
  2. 只要 i 主件物品,A(i , N) = A(i + 1 , N - A(i)的价格)
  3. 只要 i 主件、fj1, A(i , N) = A(i + 1 , N - A(i)的价格 - fj1 的价格)
  4. 只要 i 主件、fj2, A(i , N) = A(i + 1 , N - A(i)的价格 - fj2 的价格)
  5. i 主件、fj1、fj2, A(i , N) = A(i + 1 , N - A(i)的价格 - fj1 的价格 - fj2 的价格)

根据这样的理解,编写如下代码:

import java.util.*;  


// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // 注意 hasNext 和 hasNextLine 的区别
        int N = 0 ; 
        int m = 0 ;
        List<Product> products = new ArrayList();
        if(in.hasNextInt()) { // 注意 while 处理多个 case
            N = in.nextInt();
            m = in.nextInt();
        }
        for(int a = 1 ; a <= m ; a++){
            products.add(new Product(a ,in.nextInt() , in.nextInt() , in.nextInt()));
        }
        int[][] value = new int[products.size()][3];
        int[][] price = new int[products.size()][3];
        List<Product> main = component(value , price , products);
        System.out.println(maxSatisfiedSocre2(N , main , value , price));
    }
    public static  List<Product> component(int[][] value , int[][] price , List<Product> products){
        List<Product> main = new ArrayList();
        int j = 0 ;
        for(int i = 0 ; i < products.size() ; i++){
            if(products.get(i).q == 0){
                main.add(products.get(i));
                value[j][0] = products.get(i).v;
                price[j][0] = products.get(i).p;
                List<Product> c = getFj(products.get(i).idx , products);
                if(c.size() > 0){
                    value[j][1] = c.get(0).p;
                    price[j][1] = c.get(0).v;
                    if(c.size() > 1 ){
                        value[j][2] = c.get(1).p;
                        price[j][2] = c.get(1).v;
                    }
                }

                j++;
            }
        }
        return main ;
    }
    public static List<Product> getFj(int id , List<Product> products){
        List<Product> rs = new ArrayList<Product>();
        for(int i = 0 ; i < products.size() ; i++){
            if(id == products.get(i).q){
                rs.add(products.get(i));
            }
        }
        return rs ;
    }
    public static class Product{
        public int idx ;
        public int v ;
        public int p ;
        public int q ;
        public Product(int idx ,int v , int p , int q){
            this.idx = idx ;
            this.v = v ;
            this.p = p ;
            this.q = q ;
        }
    }
    // 递归版本,此解法会超时
    public static int maxSatisfiedSocre(int N ,List<Product> products , int[][] value , int[][] price){
        if(N == 0 || null == products || products.size() == 0) return 0 ;
        return process(0 , N , products , value , price);
    }
    // 动态递归的解法
    public static int maxSatisfiedSocre2(int N ,List<Product> products , int[][] value , int[][] price){
        if(N == 0 || null == products || products.size() == 0) return 0 ;
        int[][] dp = new int[products.size()][N+1];
        int p1 = -1 ;
        int p2 = -1 ;
        int p3 = -1 ;
        int p4 = -1 ;
        int idx = products.size()-1 ;
        // int j = N ;
        for(int j = N ; j >= products.get(idx).v ; j-- ){
            p1 = -1 ;
            p2 = -1 ;
            p3 = -1 ;
            p4 = -1 ;
            if( j >= products.get(idx).v){
                p1 = products.get(idx).v*products.get(idx).p ;
                // dp[idx][j - products.get(idx).v] = p1 ;
            }

            if(j >= products.get(idx).v + price[idx][1]){
                p2 = products.get(idx).v*products.get(idx).p + value[idx][1]*price[idx][1] ;
                // dp[idx][j - products.get(idx).v - price[idx][1]] = p2 ;              
            }
        
            if(j >= products.get(idx).v + price[idx][2]){
                p3 = products.get(idx).v*products.get(idx).p + value[idx][2]*price[idx][2] ;
                // dp[idx][j - products.get(idx).v - price[idx][2]] = p3 ;              
            }
                
            if(j >= products.get(idx).v + price[idx][1] + price[idx][2]){
                p4 = products.get(idx).v*products.get(idx).p + value[idx][1]*price[idx][1] + value[idx][2]*price[idx][2] ;
                // dp[idx][j - products.get(idx).v - price[idx][1] - price[idx][2]] = p4 ;
            }
            dp[idx][j] = Math.max(Math.max(p1 , p2) , Math.max(p3 , p4));
        }
        int p5 = -1 ;
        for(int i = products.size() - 2 ; i>=0  ; i--){
            for(int j = N ; j > 0 ; j--){
                p1 = -1 ;
                p2 = -1 ;
                p3 = -1 ;
                p4 = -1 ;
                p5 = -1 ;
                if( j >= products.get(i).v ){
                    p1 = products.get(i).v*products.get(i).p + dp[i+1][j - products.get(i).v];
                    // dp[i][j - products.get(i).v] = p1 ;
                }
                if(j >= products.get(i).v + price[i][1]){
                    p2 = products.get(i).v*products.get(i).p + value[i][1]*price[i][1] + dp[i+1][j - products.get(i).v - price[i][1]];
                    // dp[i][j - products.get(i).v - price[i][1]] = p2;
                }
                if(j >= products.get(i).v + price[i][2]){
                    p3 = products.get(i).v*products.get(i).p + value[i][2]*price[i][2] + dp[i+1][j - products.get(i).v - price[i][2]];
                    // dp[i][j - products.get(i).v - price[i][2]] = p3 ;                 

                }
                if(j >= products.get(i).v + price[i][1] + price[i][2]){
                    p4 = products.get(i).v*products.get(i).p + value[i][1]*price[i][1] + value[i][2]*price[i][2] + dp[i+1][j - products.get(i).v - price[i][1] - price[i][2]];
                    // dp[i][j - products.get(i).v - price[i][1] - price[i][2] ] = p4 ;  
                }
                
                // 不要 i
                p5 = dp[i+1][j];
                dp[i][j] = Math.max(Math.max(p1 , p2) , Math.max(Math.max(p3 , p4) , p5));
            }
        }
        return dp[0][N];
    }
    // 递归版本的实际实现。
    public static int process(int i , int N , List<Product> products , int[][] value , int[][] price){
        if(i + 1 == products.size()){
            int p1 = -1 ;
            int p2 = -1 ;
            int p3 = -1 ;
            int p4 = -1 ;
            if( N >= products.get(i).v){
               p1 = products.get(i).v*products.get(i).p ;
            }
            if(N >= products.get(i).v + price[i][1]){
                p2 = products.get(i).v*products.get(i).p + value[i][1]*price[i][1] ;
            }
            if(N >= products.get(i).v + price[i][2]){
                p3 = products.get(i).v*products.get(i).p + value[i][2]*price[i][2] ;
            }
            if(N >= products.get(i).v + price[i][1] + price[i][2]){
                p4 = products.get(i).v*products.get(i).p + value[i][1]*price[i][1] + value[i][2]*price[i][2] ;
            }
            return Math.max(Math.max(p1 , p2) , Math.max(p3 , p4));
        }
        int p1 = -1 ;
        int p2 = -1 ;
        int p3 = -1 ;
        int p4 = -1 ;
        // 只要 i 的作为主键
        int next = process(i+1 , N - products.get(i).v , products , value , price);
        if(-1 == next){
            next = 0 ;
        }
        if( N >= products.get(i).v ){
            p1 = products.get(i).v*products.get(i).p + next ;
        }
        if(N >= products.get(i).v + price[i][1]){
            next = process(i+1 , N - products.get(i).v - price[i][1] , products , value , price);
            if(-1 == next){
                next = 0 ;
            }
            p2 = products.get(i).v*products.get(i).p + value[i][1]*price[i][1] + next ;
        }
        if(N >= products.get(i).v + price[i][2]){
            next = process(i+1 , N - products.get(i).v - price[i][2] , products , value , price);
            if(-1 == next){
                next = 0 ;
            }
            p3 = products.get(i).v*products.get(i).p + value[i][2]*price[i][2] + next;
        }
        if(N >= products.get(i).v + price[i][1] + price[i][2]){
            next = process(i+1 , N - products.get(i).v - price[i][1] - price[i][2] , products , value , price);
            if(-1 == next){
                next = 0 ;
            }
            p4 = products.get(i).v*products.get(i).p + value[i][1]*price[i][1] + value[i][2]*price[i][2] + next;
        }
        // 不要 i
        int p5 = process(i+1 , N , products , value , price);
        return Math.max(Math.max(p1 , p2) , Math.max(p5 , Math.max(p3 , p4)));
    }
}

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

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

相关文章

用于 SQLite 的异步 I/O 模块(二十四)

返回&#xff1a;SQLite—系列文章目录 上一篇&#xff1a;SQLite的PRAGMA 声明&#xff08;二十三&#xff09; 下一篇&#xff1a;SQLite、MySQL 和 PostgreSQL 数据库速度比较&#xff08;本文阐述时间很早比较&#xff0c;不具有最新参考性&#xff09;&#xff08;二…

【数据结构|C语言版】单链表应用

前言1. 基于单链表实现通讯录1.1 知识要求1.2 功能要求 2. 代码总结2.1 SeqList.h2.2 SeqList.c2.3 Contact.h2.4 Contact.c2.5 test.c 后言 上期回顾&#xff1a;【数据结构|C语言版】单链表 前言 各位小伙伴大家好&#xff01;上期小编讲解了单链表相关知识&#xff0c;在此…

linux 设置定时任务---学习

1、设置定时任务 crontab -e 设置格式参考&#xff1a;【Linux】Linux crontab 命令定时任务设置_crontab 设置每天10:30执行-CSDN博客 测试过程&#xff1a; */1 * * * * /root/cronjob.sh 脚本内容: echo "hell0 cronjob" >> /root/test/hello.txt 实现…

腾讯云服务器CVM标准型S8实例CPU内存、网络和存储性能测评

腾讯云第八代云服务器标准型S8实例基于全新优化虚拟化平台&#xff0c;CPU采用Intel Emerald Rapids 全新处理器&#xff0c;睿频3.0GHz&#xff0c;内存采用最新DDR5&#xff0c;默认网络优化&#xff0c;最高内网收发能力达4500万pps&#xff0c;最高内网带宽可支持120Gbps。…

游戏生成式 AI:编织梦想,避开阴影

想象一下&#xff0c;一个沉浸式的游戏世界中玩家遇到的每个 NPC 都由 AI 驱动&#xff0c;他们能与玩家进行互动&#xff0c;从改变游戏体验。据 Inword 一项研究显示&#xff0c;绝大多数游戏玩家渴望这种互动&#xff0c;愿意投入更多的时间和金钱来玩这种由 AI 驱动的游戏。…

亚马逊、沃尔玛自养号测评技术解析:如何降低潜在风险

亚马逊等电商平台在全球范围内迅速扩张&#xff0c;竞争愈发激烈。为提升产品排名和销量&#xff0c;众多卖家选择采用自养号测评的策略。然而&#xff0c;自养号测评技术并非完美无缺&#xff0c;它存在着一定的技术局限性。由于缺乏对自养号原理及底层环境搭建的深入理解&…

如何在Vue3中使用H.265视频EasyPlayer.js流媒体播放器?

H5无插件流媒体播放器EasyPlayer属于一款高效、精炼、稳定且免费的流媒体播放器&#xff0c;可支持多种流媒体协议播放&#xff0c;可支持H.264与H.265编码格式&#xff0c;性能稳定、播放流畅&#xff0c;能支持WebSocket-FLV、HTTP-FLV&#xff0c;HLS&#xff08;m3u8&#…

操作系统(第五周 第一二堂总结)

目录 回顾 前景知识 概述 定义 进程和线程的关系 进程和线程的区别 线程优缺点 优点&#xff1a; 缺点&#xff1a; 易混概念 线程实现方式 线程的类型&#xff1a; ​编辑 多线程模型&#xff1a; 线程函数 头文件&#xff1a; 线程创建函数&#xff1a; 线…

k8s控制器(五)_____DaemonSet

DaemonSet控制器 DaemonSet控制器是Kubernetes中的一种控制器&#xff0c;用于确保集群中的每个节点都运行一个Pod的副本。它通常用于在整个集群中部署一些系统级别的服务&#xff1a; 在每一个node节点运行一个存储服务&#xff0c;例如gluster&#xff0c;ceph。在每一个no…

DRF视图组件(2个视图基类、5个视图扩展类、9个视图子类、视图集和路由映射)

DRF视图组件(2个视图基类、5个视图扩展类、9个视图子类、视图集和路由映射) 目录 DRF视图组件(2个视图基类、5个视图扩展类、9个视图子类、视图集和路由映射)2个视图基类mixins的5个视图扩展类generics的9个视图子类视图集自定制返回格式自动生成路由(SimpleRouter)action装饰器…

非监督学习的模型为条件概率分布P(z|x)和p(x|z)的区别

在无监督学习中&#xff0c;假设X是输入空间&#xff0c;Z是输出的隐式结构空间&#xff0c;要学习的模型非概率模型情况可以表示为函数zg(x)&#xff0c;概率模型情况下表示为条件概率分布P&#xff08;z|x&#xff09;或p(x∣z)&#xff0c;它们 都可以用来描述数据中的潜在结…

[ROS 系列学习教程] 建模与仿真 - URDF 语法介绍

ROS 系列学习教程(总目录) 本文目录 一、robot标签二、link标签三、joint标签 URDF文件中使用XML格式描述的机器人模型&#xff0c;下面介绍URDF的XML标签。 一、robot标签 机器人描述文件中的根元素必须是robot&#xff0c;所有其他元素必须封装在其中。 属性 name&#x…

JetBrains Rider 2024.1 发布 - 快速且强大的跨平台 .NET IDE

JetBrains Rider 2024.1 发布 - 快速且强大的跨平台 .NET IDE 请访问原文链接&#xff1a;JetBrains Rider 2024.1 (macOS, Linux, Windows) - 快速且强大的跨平台 .NET IDE&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&#xff1a;sysin.org Jet…

jpa使用Querydsl需要规避的一些坑

在使用Spring Data JPA时&#xff0c;通常会使用Querydsl来构建类型安全的查询。在Querydsl中&#xff0c;为了区分实体类与Querydsl查询类&#xff0c;习惯上会给查询类的前缀添加一个"Q"&#xff0c;表示该类是一个查询类。这样做可以有效地避免实体类与查询类之间…

数据结构和算法(哈希表和图(A*算法精讲))

一 、哈希表 1.1 哈希表原理精讲 哈希表-散列表&#xff0c;它是基于快速存取的角度设计的&#xff0c;也是一种典型的“空间换时间”的做法 键(key)&#xff1a; 组员的编号如&#xff0c;1、5、19。。。 值(value)&#xff1a; 组员的其它信息&#xff08;包含性别、年龄和…

pyqt实现星三角减压启动

这个对于plc上实现是非常容易得。它本来就是逻辑控制器&#xff0c;如果用代码实现它&#xff0c;该怎么做呢&#xff1f;这个实现起来看似简单&#xff0c;实则是有不少坑的&#xff08;大神除外&#xff09;。我一直想用类来封装&#xff0c;让它继承QObject,为啥非要继承QOb…

电信网络如何异地共享文件?

电信异地共享文件是指在不同地区的电信网络下&#xff0c;通过使用特定技术实现文件的共享和传输。在传统的网络环境中&#xff0c;由于网络限制和复杂的网络设置&#xff0c;实现跨地区的文件共享是一个具有挑战性的任务。随着技术的不断进步&#xff0c;现在可以利用电信异地…

Spring Boot | SpringBoot对 “SpringMVC“的 “整合支持“、SpringMVC“功能拓展实现“

目录: SpringMVC 的 “整合支持” ( 引入"Web依赖启动器"&#xff0c;几乎可以在无任何额外的配置的情况下进行"Web开发")1.SpringMVC "自动配置" 介绍 ( 引入Web依赖启动器"后&#xff0c;SpringBoot会自动进行一些“自动配置”&#xff0…

文章解读与仿真程序复现思路——中国电机工程学报EI\CSCD\北大核心《应用图论建模输电网的电力现货市场出清模型》

本专栏栏目提供文章与程序复现思路&#xff0c;具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 电网论文源程序-CSDN博客电网论文源…

【cuda\cudnn安装教程】以及环境变量设置(以cuda11.8为例)

【cuda\cudnn安装教程】以cuda11.8为例 cuda11.8安装 安装的时候一切都是按默认安装就好&#xff0c;地址也是默认路径 cudnn安装 下载需要登陆&#xff0c;按要求注册就好 将cudnn压缩包中的内容复制到cuda的安装路径中&#xff0c;进行替换&#xff0c;如下图 验证cuda是否…