【算法】动态规划算法详解与示例(python、go、java)

动态规划(Dynamic Programming,DP)是一种算法设计方法,常用于解决最优化问题。它将复杂问题分解为更简单的子问题,通过存储已解决的子问题的结果来避免重复计算,从而提高效率。本文将详细介绍动态规划的基本概念,并使用 Python、Go 和 Java 提供具体案例。

一、动态规划的基本概念

动态规划的核心思想是将一个复杂问题分解为更简单的子问题,然后通过解决这些子问题来构造原问题的解。动态规划通常适用于具有重叠子问题和最优子结构性质的问题。

1. 重叠子问题

如果一个问题可以被分解成多个子问题,而这些子问题在整个求解过程中被重复求解,则称为重叠子问题。

2. 最优子结构

如果一个问题的最优解可以由其子问题的最优解有效构建出来,则称为最优子结构。

二、动态规划的基本步骤

动态规划通常包括以下步骤:

  1. 定义状态:确定用什么样的状态来表示问题。
  2. 状态转移方程:建立状态之间的关系。
  3. 初始状态:设置边界条件。
  4. 计算结果:通过状态转移方程计算最终结果。

三、经典案例:斐波那契数列

 斐波那契数列是动态规划的经典例子。其定义为:F(0) = 0, F(1) = 1,F(n) = F(n-1) + F(n-2)。

1. Python 实现

def fibonacci(n):
    # 初始化一个数组来存储斐波那契数
    fib = [0] * (n + 1)
    fib[1] = 1

    # 填充数组
    for i in range(2, n + 1):
        fib[i] = fib[i - 1] + fib[i - 2]
    
    return fib[n]

# 测试
n = 10
print(f"Fibonacci of {n} is {fibonacci(n)}")  # 输出: Fibonacci of 10 is 55

2. Go 实现

package main

import "fmt"

func fibonacci(n int) int {
    fib := make([]int, n+1)
    fib[1] = 1

    for i := 2; i <= n; i++ {
        fib[i] = fib[i-1] + fib[i-2]
    }
    
    return fib[n]
}

func main() {
    n := 10
    fmt.Printf("Fibonacci of %d is %d\n", n, fibonacci(n))  // 输出: Fibonacci of 10 is 55
}

3. Java 实现

public class Fibonacci {
    public static int fibonacci(int n) {
        int[] fib = new int[n + 1];
        fib[1] = 1;

        for (int i = 2; i <= n; i++) {
            fib[i] = fib[i - 1] + fib[i - 2];
        }

        return fib[n];
    }

    public static void main(String[] args) {
        int n = 10;
        System.out.println("Fibonacci of " + n + " is " + fibonacci(n)); // 输出: Fibonacci of 10 is 55
    }
}

四、另一个经典案例:0-1 背包问题

0-1 背包问题是动态规划中的经典问题,描述为:给定一个背包和一些物品,每个物品有一个重量和价值,目标是找到装入背包的物品,使得总价值最大。

1. Python 实现

def knapsack(weights, values, capacity):
    n = len(weights)
    # 创建一个二维数组来存储最大价值
    dp = [[0 for _ in range(capacity + 1)] for _ in range(n + 1)]

    # 填充 dp 数组
    for i in range(1, n + 1):
        for w in range(1, capacity + 1):
            if weights[i - 1] <= w:
                dp[i][w] = max(dp[i - 1][w], dp[i - 1][w - weights[i - 1]] + values[i - 1])
            else:
                dp[i][w] = dp[i - 1][w]

    return dp[n][capacity]

# 测试
weights = [1, 2, 3]
values = [10, 15, 40]
capacity = 6
print(f"Maximum value in Knapsack is {knapsack(weights, values, capacity)}")  # 输出: Maximum value in Knapsack is 55

2. Go 实现

package main

import "fmt"

func knapsack(weights []int, values []int, capacity int) int {
    n := len(weights)
    // 创建一个二维数组来存储最大价值
    dp := make([][]int, n+1)
    for i := range dp {
        dp[i] = make([]int, capacity+1)
    }

    // 填充 dp 数组
    for i := 1; i <= n; i++ {
        for w := 1; w <= capacity; w++ {
            if weights[i-1] <= w {
                dp[i][w] = max(dp[i-1][w], dp[i-1][w-weights[i-1]]+values[i-1])
            } else {
                dp[i][w] = dp[i-1][w]
            }
        }
    }

    return dp[n][capacity]
}

func max(a, b int) int {
    if a > b {
        return a
    }
    return b
}

func main() {
    weights := []int{1, 2, 3}
    values := []int{10, 15, 40}
    capacity := 6
    fmt.Printf("Maximum value in Knapsack is %d\n", knapsack(weights, values, capacity)) // 输出: Maximum value in Knapsack is 55
}

3. Java 实现

public class Knapsack {
    public static int knapsack(int[] weights, int[] values, int capacity) {
        int n = weights.length;
        int[][] dp = new int[n + 1][capacity + 1];

        for (int i = 1; i <= n; i++) {
            for (int w = 1; w <= capacity; w++) {
                if (weights[i - 1] <= w) {
                    dp[i][w] = Math.max(dp[i - 1][w], dp[i - 1][w - weights[i - 1]] + values[i - 1]);
                } else {
                    dp[i][w] = dp[i - 1][w];
                }
            }
        }

        return dp[n][capacity];
    }

    public static void main(String[] args) {
        int[] weights = {1, 2, 3};
        int[] values = {10, 15, 40};
        int capacity = 6;
        System.out.println("Maximum value in Knapsack is " + knapsack(weights, values, capacity)); // 输出: Maximum value in Knapsack is 55
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值