当前位置:实例文章 » 其他实例» [文章]代码随想录算法训练营第十九天 | 动态规划系列5,6,7,8

代码随想录算法训练营第十九天 | 动态规划系列5,6,7,8

发布人:shili8 发布时间:2024-12-26 14:34 阅读次数:0

**代码随想录算法训练营第十九天**

**动态规划系列5-8**

在前面的几篇文章中,我们已经学习了动态规划的基本概念、应用场景以及几个经典问题的解决方案。今天,我们将继续深入探讨动态规划的主题,重点介绍四个新的问题:最长上升子序列(Longest Increasing Subsequence, LIS)、最短路径和最长路径(Shortest Path and Longest Path)、背包问题(Knapsack Problem)以及最小割(Minimum Cut)。

### 最长上升子序列(LIS)

**问题描述**

给定一个整数数组 `arr`,要求找到其中的最长上升子序列(LIS)。也就是说,我们需要从原数组中找出一段连续的子序列,使得每两个相邻元素都满足递增关系。

**动态规划解决方案**

我们可以使用一个长度为 `n` 的数组 `dp` 来表示最长上升子序列的长度,其中 `n` 是原数组的大小。对于每个位置 `i`,我们需要找到从 `arr[0]` 到 `arr[i-1]` 中能组成的最长上升子序列的长度,并将其存储在 `dp[i]` 中。

def longest_increasing_subsequence(arr):
 n = len(arr)
 dp = [1] * n # 初始化dp数组 for i in range(1, n):
 for j in range(i):
 if arr[i] > arr[j]:
 dp[i] = max(dp[i], dp[j] +1)

 return max(dp) # 返回最长上升子序列的长度


**时间复杂度分析**

该算法的时间复杂度为 O(n^2),因为我们需要对每个位置 `i` 进行 O(n) 次比较。

### 最短路径和最长路径**问题描述**

给定一个有向图 `graph`,要求找到从源点到目标点的最短路径长度和最长路径长度。

**动态规划解决方案**

我们可以使用两个长度为 `n` 的数组 `dp_shortest` 和 `dp_longest` 来表示最短路径长度和最长路径长度,其中 `n` 是图中顶点的数量。对于每个位置 `i`,我们需要找到从源点到 `i` 的最短路径长度和最长路径长度,并将其存储在 `dp_shortest[i]` 和 `dp_longest[i]` 中。

def shortest_and_longest_path(graph):
 n = len(graph)
 dp_shortest = [float('inf')] * n # 初始化dp_shortest数组 dp_longest = [0] * n # 初始化dp_longest数组 dp_shortest[0] =0 # 源点的最短路径长度为0 dp_longest[0] =0 # 源点的最长路径长度为0 for i in range(1, n):
 for j in range(i):
 if graph[i][j] != float('inf'):
 dp_shortest[i] = min(dp_shortest[i], dp_shortest[j] + graph[i][j])
 dp_longest[i] = max(dp_longest[i], dp_longest[j] + graph[i][j])

 return dp_shortest[-1], dp_longest[-1] # 返回最短路径长度和最长路径长度


**时间复杂度分析**

该算法的时间复杂度为 O(n^2),因为我们需要对每个位置 `i` 进行 O(n) 次比较。

### 背包问题**问题描述**

给定一个物品集合 `items`,要求找到能装入背包中最多价值的子集,并且背包的容量为 `capacity`。

**动态规划解决方案**

我们可以使用一个长度为 `n+1` 的数组 `dp` 来表示能装入背包中最多价值的子集,其中 `n` 是物品集合的大小。对于每个位置 `i`,我们需要找到从 `items[0]` 到 `items[i-1]` 中能组成的最多价值的子集,并将其存储在 `dp[i]` 中。

def knapsack(items, capacity):
 n = len(items)
 dp = [0] * (n +1) # 初始化dp数组 for i in range(1, n +1):
 for j in range(capacity +1):
 if items[i -1][0] <= j:
 dp[i] = max(dp[i], dp[i -1])
 dp[i] = max(dp[i], dp[i -1] + items[i -1][1])

 return dp[-1] # 返回能装入背包中最多价值的子集


**时间复杂度分析**

该算法的时间复杂度为 O(n*capacity),因为我们需要对每个位置 `i` 进行 O(capacity) 次比较。

### 最小割**问题描述**

给定一个有向图 `graph`,要求找到最小割的大小。

**动态规划解决方案**

我们可以使用两个长度为 `n+1` 的数组 `dp_mincut` 和 `dp_maxflow` 来表示最小割的大小和最大流的大小,其中 `n` 是图中顶点的数量。对于每个位置 `i`,我们需要找到从源点到 `i` 的最小割的大小和最大流的大小,并将其存储在 `dp_mincut[i]` 和 `dp_maxflow[i]` 中。

def min_cut(graph):
 n = len(graph)
 dp_mincut = [float('inf')] * (n +1) # 初始化dp_mincut数组 dp_maxflow = [0] * (n +1) # 初始化dp_maxflow数组 dp_mincut[0] =0 # 源点的最小割大小为0 dp_maxflow[0] =0 # 源点的最大流大小为0 for i in range(1, n +1):
 for j in range(i):
 if graph[i][j] != float('inf'):
 dp_mincut[i] = min(dp_mincut[i], dp_mincut[j] + graph[i][j])
 dp_maxflow[i] = max(dp_maxflow[i], dp_maxflow[j] + graph[i][j])

 return dp_mincut[-1] # 返回最小割的大小


**时间复杂度分析**

该算法的时间复杂度为 O(n^2),因为我们需要对每个位置 `i` 进行 O(n) 次比较。

以上就是本文关于动态规划系列5-8的内容。这些问题都是经典的动态规划问题,通过使用动态规划,我们可以有效地解决这些问题,并且得到最优解。

其他信息

其他资源

Top