十大算法 —— 分治 动态规划 KMP 贪心 普利姆

本文详细介绍了分治算法、动态规划、KMP字符串匹配、贪心算法和普利姆算法。通过汉诺塔问题解释分治,背包问题阐述动态规划,KMP算法解决字符串匹配,贪心算法解决集合覆盖问题,以及普利姆算法在修路问题中的应用。每个算法都包含基本原理、案例分析、思路解析及代码实现。
摘要由CSDN通过智能技术生成

1. 分治算法 —— 汉诺塔问题
1. 分治算法的基本步骤

分治算法在每一层递归上都有三个步骤:

  • 分解:将原问题分解为若干个规模较小,相互独立,与原问题形式相同的子问题;
  • 解决:若子问题规模较小而任意被解决,则直接解决,否则递归的解决各个子问题;
  • 合并:将各个子问题的解合并为原问题的解
2. 经典案例 —— 汉诺塔

将 柱子 A 上的所有盘子移动到 柱子 C 上。
在这里插入图片描述
思路分析:

  • 如果只有一个盘子,将这一个盘子从 A -> C上
  • 如果有多个盘子,我们总是可以将这些盘子看作是两部分,第一部分:最下边的一个盘子,第二部分:剩余的所有盘子
    • 先将最上边的盘子(第二部分)从 A -> B
    • 再将最下边的盘子(第一部分)从 A -> C
    • 最后将上边的盘子(B塔上的第二部分所有盘子)从 B -> C
汉诺塔问题代码:
package dac;

public class HanoiTower {
   
    public static void main(String[] args) {
   
        hanoiTower(5, 'A','B','C');
    }
    /**
     * 将盘子从 a -> c
     * @param num 盘的数量
     * @param a 开始的柱子
     * @param b 中间辅助的柱子
     * @param c 目标柱子
     */
    public static void hanoiTower(int num, char a, char b, char c){
   
        if(num == 1){
   
            System.out.println("第 1 个盘从 " + a + " -> " + c);
        } else {
   
            hanoiTower(num - 1, a, c, b);
            System.out.println("第 " + num + " 个盘从 " + a + " -> " + c);
            hanoiTower(num - 1, b, a, c);
        }
    }
}
2. 动态规划 —— 背包问题
1. 动态规划算法的介绍
  • 动态规划算法的核心思想:将大问题划分为小问题进行解决,从而一步步获取最优解的处理算法
  • 与分治算法的区别:适合用动态规划求解的问题,经过分解往往不是相互独立的即下一个子阶段的求解是建立在上一个子阶段的解的基础上进一步的求解。
  • 动态规划问题可以通过填表的方法来逐步推进,得到最优解。
2. 经典案例 —— 背包问题

现有一个背包,容量为 4 磅,现有如下物品
在这里插入图片描述
1)求达到的目标为装入的背包的总价值最大,并且重量不超出背包的容量
2)要求装入的物品不能重复
3)通常的背包问题主要是指一个给定容量的背包、若干具有一定价值和重量的物品,选择物品放入背包使物品的价值最大。这里的背包问题属于01背包,即没有物品最多只能放一个,还有一种完全背包,即没有物品都有无限件可用,即可以重复

3. 思路分析

设置物品的重量数组为 w[i],物品的价格数组为 val[i],设v[i][j] 表示在前 i 个物品中能够装入容量为 j 的背包中的最大价值,即表中的 v[i][j] 数据表示背包为 j 重量下,有 i 件物品的情况下的最大价值。
填表分析:
在这里插入图片描述

  • v[i][0] = v[0][j] = 0; //表示的就是 表格 中第一行和第一列都是 0
  • 当 w[j] > j 时:v[i][j] = v[i - 1][j]; // 表示准备新增的商品的重量大于 当前背包的容量,就直接使用上一个单元格的装入策略;
  • 当 w[j] <= j 时:v[i][j] = max{v[i - 1][j],val[i] + v[i - 1][j - w[i]]}; // 表示的是准备加入的新增的商品的容量小于等于当前背包的容量
    • v[i - 1][j] —— 就是上一个单元格的装入策略
    • val[i] + v[i - 1][j - w[i]] 中,val[i] —— 当前物品的重量,v[i - 1][j - w[i]] ,表示的是在当前物品满足背包的容量下,若背包还有剩余的空间,剩余空间的最大价值。
4. 代码实现:
package dynamic;

public class KnapsackProblem {
   
    public static void main(String[] args) {
   
        int[] w = {
   1, 4, 3}; // 物品的重量
        int[] val = {
   1500, 3000, 2000}; // 物品的价值
        int m = w.length; // 物品的个数
        int n = 4; // 背包的容量

        int[][] v = new int[m + 1][n + 1];
        // 用来记录存放的商品的情况
        int[][] path = new int[m + 1][n + 1];

        for(int i = 0; i < v.length; i++){
    // 第一列设置为 0
            v[i][0] = 0;
        }
        for(int i = 0; i < v[0].length; i++){
    // 第一行设置为 0
            v[0][i] = 0;
        }

        for(int i = 1; i < v.length; i++){
   
            for(int j = 1; j < v[i].length; j++){
   
                if(j < w[i - 1]){
   
                    v[i][j] = v[i - 1][j];
                } else {
   
                    // v[i][j] = Math.max(v[i - 1][j], val[i - 1] + v[i - 1][j - w[i - 1]]);
                    // 为了更好的记录应该放入的是哪些商品,应该采取下面的方法 —— 这两种方法都能计算价值
                    if(v[i - 1][j] > val[i - 1] + v[i - 1][
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值