【CS.AL】算法核心之分治算法:从入门到进阶

文章目录

    • 1. 概述
    • 2. 适用场景
    • 3. 设计步骤
    • 4. 优缺点
    • 5. 典型应用
    • 6. 题目和代码示例
      • 6.1 简单题目:归并排序
      • 6.2 中等题目:最近点对问题
      • 6.3 困难题目:分数背包问题
    • 7. 题目和思路表格
    • 8. 总结
    • References

1000.01.CS.AL.1.4-核心-DivedeToConquerAlgorithm-Created: 2024-06-15.Saturday09:35
在这里插入图片描述

1. 概述

分治算法(Divide and Conquer)是一种重要的算法设计思想,其核心思想是将一个复杂的问题分解为多个相对简单的小问题,通过解决这些小问题再合并其结果,从而得到原问题的解。分治算法的典型特征是递归,常用于求解具有重复子问题性质的问题。

2. 适用场景

分治算法适用于以下场景:

  • 问题可以分解为若干个规模较小且相互独立的子问题。
  • 这些子问题的解可以合并得到原问题的解。
  • 具有最优子结构性质,即子问题的最优解可以合成原问题的最优解。

3. 设计步骤

  1. 分解(Divide):将原问题分解为若干个子问题,这些子问题的结构与原问题相同但规模较小。
  2. 解决(Conquer):递归地解决这些子问题。当子问题的规模足够小时,直接解决。
  3. 合并(Combine):将子问题的解合并,得到原问题的解。

4. 优缺点

  • 优点:分治算法的递归思想使其在解决许多复杂问题时表现出色。具有良好的可扩展性和并行计算的潜力。
  • 缺点:对于某些问题,分治算法可能会引入额外的开销,如递归调用栈和合并步骤的时间复杂度。

5. 典型应用

  • 归并排序(Merge Sort):一种高效的排序算法,利用分治思想将数组分为两半,递归地排序并合并。
  • 快速排序(Quick Sort):另一种高效的排序算法,选择一个基准元素,将数组分为两部分,递归排序。
  • 最近点对问题(Closest Pair Problem):在平面上找到距离最近的两点,分治法可以将时间复杂度降至 O(nlog⁡n)O(n \log n)O(nlogn)。
  • 矩阵乘法(Strassen’s Algorithm):一种用于矩阵乘法的分治算法,降低了时间复杂度。

6. 题目和代码示例

6.1 简单题目:归并排序

题目描述:实现归并排序算法,对给定的数组进行排序。

代码示例

#include <iostream>
#include <vector>// 函数声明
void mergeSort(std::vector<int>& arr, int left, int right);
void merge(std::vector<int>& arr, int left, int mid, int right);int main() {std::vector<int> arr = {38, 27, 43, 3, 9, 82, 10};mergeSort(arr, 0, arr.size() - 1);for (int num : arr) {std::cout << num << " ";}std::cout << std::endl;return 0;
}// 归并排序:递归地将数组分成两半进行排序
void mergeSort(std::vector<int>& arr, int left, int right) {if (left < right) {int mid = left + (right - left) / 2;mergeSort(arr, left, mid);mergeSort(arr, mid + 1, right);merge(arr, left, mid, right);}
}// 合并两个已排序的子数组
void merge(std::vector<int>& arr, int left, int mid, int right) {int n1 = mid - left + 1;int n2 = right - mid;std::vector<int> L(n1), R(n2);for (int i = 0; i < n1; ++i) {L[i] = arr[left + i];}for (int j = 0; j < n2; ++j) {R[j] = arr[mid + 1 + j];}int i = 0, j = 0, k = left;while (i < n1 && j < n2) {if (L[i] <= R[j]) {arr[k] = L[i++];} else {arr[k] = R[j++];}++k;}while (i < n1) {arr[k++] = L[i++];}while (j < n2) {arr[k++] = R[j++];}
}

Others.

def merge_sort(arr):if len(arr) > 1:mid = len(arr) // 2left_half = arr[:mid]right_half = arr[mid:]merge_sort(left_half)merge_sort(right_half)i = j = k = 0while i < len(left_half) and j < len(right_half):if left_half[i] < right_half[j]:arr[k] = left_half[i]i += 1else:arr[k] = right_half[j]j += 1k += 1while i < len(left_half):arr[k] = left_half[i]i += 1k += 1while j < len(right_half):arr[k] = right_half[j]j += 1k += 1# 示例
arr = [38, 27, 43, 3, 9, 82, 10]
merge_sort(arr)
print(arr)  # 输出: [3, 9, 10, 27, 38, 43, 82]

6.2 中等题目:最近点对问题

题目描述:在平面上找到距离最近的两点,时间复杂度为 O(nlog⁡n)。

代码示例

#include <iostream>
#include <vector>
#include <cmath>
#include <algorithm>struct Point {int x, y;
};double dist(const Point& p1, const Point& p2) {return std::sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y));
}double closestPair(std::vector<Point>& points, int left, int right) {if (right - left <= 3) {double minDist = std::numeric_limits<double>::infinity();for (int i = left; i < right; ++i) {for (int j = i + 1; j <= right; ++j) {minDist = std::min(minDist, dist(points[i], points[j]));}}return minDist;}int mid = left + (right - left) / 2;double d1 = closestPair(points, left, mid);double d2 = closestPair(points, mid + 1, right);double d = std::min(d1, d2);std::vector<Point> strip;for (int i = left; i <= right; ++i) {if (std::abs(points[i].x - points[mid].x) < d) {strip.push_back(points[i]);}}std::sort(strip.begin(), strip.end(), [](const Point& p1, const Point& p2) {return p1.y < p2.y;});double minDist = d;for (size_t i = 0; i < strip.size(); ++i) {for (size_t j = i + 1; j < strip.size() && (strip[j].y - strip[i].y) < minDist; ++j) {minDist = std::min(minDist, dist(strip[i], strip[j]));}}return minDist;
}int main() {std::vector<Point> points = {{2, 3}, {12, 30}, {40, 50}, {5, 1}, {12, 10}, {3, 4}};std::sort(points.begin(), points.end(), [](const Point& p1, const Point& p2) {return p1.x < p2.x;});std::cout << "最近点对距离: " << closestPair(points, 0, points.size() - 1) << std::endl;return 0;
}

Others.

import mathdef dist(p1, p2):return math.sqrt((p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2)def closest_pair(points):def closest_pair_recursive(points):if len(points) <= 3:return min((dist(p1, p2), (p1, p2)) for i, p1 in enumerate(points) for p2 in points[i+1:])[1]mid = len(points) // 2left_half = points[:mid]right_half = points[mid:](d1, pair1) = closest_pair_recursive(left_half)(d2, pair2) = closest_pair_recursive(right_half)d = min(d1, d2)pair = pair1 if d1 < d2 else pair2strip = [p for p in points if abs(p[0] - points[mid][0]) < d]strip.sort(key=lambda p: p[1])for i in range(len(strip)):for j in range(i+1, len(strip)):if strip[j][1] - strip[i][1] >= d:breakd_new = dist(strip[i], strip[j])if d_new < d:d = d_newpair = (strip[i], strip[j])return d, pairpoints.sort(key=lambda p: p[0])return closest_pair_recursive(points)[1]# 示例
points = [(2, 3), (12, 30), (40, 50), (5, 1), (12, 10), (3, 4)]
print(closest_pair(points))  # 输出: ((2, 3), (3, 4))

6.3 困难题目:分数背包问题

题目描述:给定物品的重量和价值,求在背包容量限制下的最大价值,物品可以分割。

代码示例

#include <iostream>
#include <vector>
#include <algorithm>struct Item {double value;double weight;
};double fractionalKnapsack(std::vector<Item>& items, double capacity) {std::sort(items.begin(), items.end(), [](const Item& a, const Item& b) {return (a.value / a.weight) > (b.value / b.weight);});double totalValue = 0;for (const auto& item : items) {if (capacity >= item.weight) {capacity -= item.weight;totalValue += item.value;} else {totalValue += item.value * (capacity / item.weight);break;}}return totalValue;
}int main() {std::vector<Item> items = {{60, 10}, {100, 20}, {120, 30}};double capacity = 50;std::cout << "背包的最大价值: " << fractionalKnapsack(items, capacity) << std::endl;return 0;
}

Others.

def fractional_knapsack(values, weights, capacity):items = list(zip(values, weights))items.sort(key=lambda x: x[0] / x[1], reverse=True)total_value = 0for value, weight in items:if capacity >= weight:capacity -= weighttotal_value += valueelse:total_value += value * (capacity / weight)breakreturn total_value# 示例
values = [60, 100, 120]
weights = [10, 20, 30]
capacity = 50
print(fractional_knapsack(values, weights, capacity))  # 输出: 240.0

7. 题目和思路表格

序号题目题目描述分治策略代码实现
1归并排序对给定的数组进行排序递归地将数组分成两半进行排序代码
2最近点对问题找到距离最近的两点将点集合递归地分成两半代码
3分数背包问题求在背包容量限制下的最大价值每次选择单位重量价值最高的物品代码
4快速排序高效排序算法选择一个基准元素,将数组分为两部分,递归排序代码
5矩阵乘法用于矩阵乘法将矩阵分成更小的子矩阵,递归计算-
6求逆序对数量统计数组中的逆序对个数使用分治法将数组分成两半,递归统计逆序对-
7最大子序和找出最大和的连续子序列将序列递归地分成两半,合并子序列的结果-
8大整数乘法实现高效的大整数乘法使用Karatsuba算法,将大整数分成两部分进行递归计算-
9二维平面上的最近点对在平面上找到距离最近的两点将点集合递归地分成两半,合并结果-
10棋盘覆盖问题用L型骨牌覆盖2^n * 2^n的棋盘将棋盘递归地分成四部分,覆盖部分棋盘-

8. 总结

分治算法是一种强大的算法设计思想,能够高效地解决许多复杂的问题。通过将问题分解为更小的子问题,分治算法不仅能够降低时间复杂度,还具有良好的可扩展性。在实际应用中,理解和掌握分治算法的思想和典型应用,对于解决各种问题具有重要意义。通过本文的例子和思路,相信读者能够深入理解分治算法的关键概念,并灵活应用于实际问题中。

References

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

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

相关文章

JavaScript 数组操作和数学计算

计算数组平均值 使用 reduce 方法 const numbers [1, 2, 3, 4, 5]; const sum numbers.reduce((accumulator, currentValue) > accumulator currentValue, 0); const average sum / numbers.length; console.log(average); // 输出: 3使用 forEach 方法 const number…

字符串格式化的精度控制

我们可以用辅助符号m.n来控制宽度和精度&#xff0c;m控制宽度&#xff0c;若是宽度小于数字本身&#xff0c;不生效。 n控制小数点精度&#xff0c;要求是数字&#xff0c;会进行小数的四舍五入例如%5d&#xff08;数字宽度为5空格空格111&#xff09;&#xff0c;%2.3f&…

汇编语言程序设计 - 输入两个字数据(16位的数)X,Y,计算Z=X+Y,并把Z的结果显示出来

80x86汇编习题 题目描述&#xff1a;输入两个字数据&#xff08;16位的数&#xff09;X,Y&#xff0c;计算ZXY&#xff0c;并把Z的结果显示出来。提示&#xff1a;X&#xff0c;Y的输入可以是任何进制。 思路&#xff1a; 1&#xff0c;总共输入两个数 2&#xff0c;每个数…

Python兴趣编程百例:手把手带你开发一个图片转字符图的小工具

在数字世界的无尽探索中&#xff0c;我们时常被那些看似平凡的技术所启发&#xff0c;它们如同星辰般点缀着我们的创意天空。今天&#xff0c;我突发奇想&#xff0c;想要用Python开发一个将图片转化为字符画的小工具。这不仅是一次技术的实践&#xff0c;更是一场艺术与科技的…

多客陪玩系统源码支持二次开发陪玩预约系统搭建,打造专业游戏陪玩平台

简述 随着电竞行业的快速发展&#xff0c;电竞陪玩APP正在逐渐成为用户在休闲娱乐时的首选。为了吸引用户和提高用户体验&#xff0c;电竞陪玩APP开发需要定制一些特色功能&#xff0c;并通过合适的盈利模式来获得收益。本文将为您介绍电竞陪玩APP开发需要定制的特色功能以及常…

LiveCharts2:简单灵活交互式且功能强大的.NET图表库

前言 之前的文章中提到过ScottPlot、与oxyplot&#xff0c;这两个是比较常用的.NET图表库&#xff0c;今天介绍一款新的.NET图表库&#xff1a;LiveCharts2。 LiveCharts2介绍 LiveCharts2 是一个现代化的数据可视化库&#xff0c;用于创建动态和交互式图表&#xff0c;支持…

编程输出中间变量:深度解析与实战应用

编程输出中间变量&#xff1a;深度解析与实战应用 在编程过程中&#xff0c;中间变量是一个至关重要的概念。它们不仅有助于我们更好地理解和组织代码&#xff0c;还能提高程序的效率和可读性。那么&#xff0c;编程输出中间变量究竟是什么呢&#xff1f;本文将从四个方面、五…

一小时搞定JavaScript(2)——DOM与BOM的应用

前言,本篇文章是依据bilibili博主(波波酱老师)的学习笔记,波波酱老师讲的很好,很适合速成!!! 本篇文章会与java进行对比学习,因为JS中很多语法和java是相同的,所以大家最好熟悉Java语言后再来进行学习,效果更佳,见效更快. 文章目录 5.DOM和BOM5.1 DOM5.1.1传统元素获取5.1.2 C…

upload.dragger组件 拖拽上传到上传区域外时,浏览器自带下载、预览文件,如何禁止该默认事件【一步解决】

只需在非上传区域加下面两个事件&#xff0c;阻止默认行为 onDragOver{(e: any) > e.preventDefault()}//阻止浏览器默认拖拽下载事件onDrop{(e: any) > e.preventDefault()}>例如&#xff0c;我的拖拽上传区域在Modal内部&#xff0c;在modal外部加一个div 并指定上…

高考志愿填报,是选好专业,还是选好学校?过来人给你说说

分数限制下&#xff0c;选好专业还是选好学校&#xff1f; 到底是先选专业还是先选学校&#xff0c;是让考生及家长一直拿不准、辨不清的问题&#xff0c;是优先考虑学校还是专业&#xff0c;上了好学校&#xff0c;专业不喜欢就业前景不理想&#xff0c;怎么办&#xff1f;为…

【未来已来】AI大模型革命:向量数据库如何重塑智能世界?

在人工智能的浪潮中,向量数据库正成为推动AI大模型发展的幕后英雄。这不是简单的技术升级,而是一场关于智能未来的革命。本文将带您深入了解向量数据库如何成为AI大模型的核心竞争力,以及它如何助力我们在智能化的道路上加速前进。 向量数据库:AI大模型的心脏 想象一下…

vue echarts画多柱状图+多折线图

<!--多柱状图折线图--> <div class"echarts-box" id"multiBarPlusLine"></div>import * as echarts from echarts;mounted() {this.getMultiBarPlusLine() },getMultiBarPlusLine() {const container document.getElementById(multiBar…

Vue 3 的各生命周期使用场景

Vue 3 的生命周期相比于 Vue 2 有所不同&#xff0c;主要是因为 Vue 3 引入了 Composition API&#xff0c;改变了组件的书写方式和生命周期的调用顺序。以下是 Vue 3 中常用的生命周期钩子及其使用场景的通俗解释&#xff1a; ** 更新阶段 ** onBeforeUpdate 什么时候调用&a…

图书管理系统代码(Java)

1、运行演示 QQ2024528-205028-HD 详细讲解在这篇博客&#xff1a;JavaSE&#xff1a;图书管理系统-CSDN博客 2、所建的包 3、Java代码 3.1 book包 3.1.1 Book类代码 package book;/*** Created with IntelliJ IDEA.* Description:* User: dings* Date: 2024-05-13* Time:…

MyBatis 自定义映射 ResultMap:字段与属性的映射详解

在 MyBatis 框架中&#xff0c;ResultMap是一个非常强大的功能&#xff0c;它允许我们自定义SQL查询结果与Java对象之间的映射关系。特别是在数据库字段名和Java对象属性名不一致时&#xff0c;ResultMap能够帮助我们精确地映射数据。 ResultMap 的基本使用 若字段名和实体类…

量化交易之日内回转策略:如何利用MACD指标实现盈利?

哈喽,大家好,我是木头左! 日内回转策略是一种短线交易策略,其核心思想是在一天内通过买入和卖出股票来实现利润。这种策略的主要优点是可以在短期内获取较高的收益,同时风险相对较小。日内回转策略主要适用于个股波动较大、流动性较好的股票。本文将详细介绍日内回转策略的…

押注“人类终极能源”!OpenAI与核聚变公司Helion Energy洽谈“购买大量”聚变能源

内容提要 在当下&#xff0c;由 AI 引发的新一轮能源危机已经不再是一个小概率的“黑天鹅”事件&#xff0c;而是一头正在向我们猛冲而来的“灰犀牛”。 文章正文 Helion Energy&#xff0c;是一家总部位于美国华盛顿州埃弗雷特的能源创业公司。 这家成立于 2013 年的公司在…

GPU性能相关的工具

GPU性能相关的工具 GPU的性能测试工具比较多&#xff0c;已知的各个开发厂家是有自己开发的性能测试工具&#xff0c;一般市场上开源或通用的性能测试工具&#xff0c;主要是跑定制的渲染场景&#xff0c;统计平均帧率&#xff0c;经过包装得到跑分值。 整体上可以分成两类&am…

华为Atlas NPU ffmpeg 编译安装

处理器&#xff1a;鲲鹏920 NPU&#xff1a;昇腾 310P3 操作系统&#xff1a;Kylin Linux Advanced Server V10 CANN&#xff1a;Ascend-cann-toolkit_8.0.RC1_linux-aarch64.run FFmpeg&#xff1a;AscendFFmpegPlugin(不要用AscendFFmpeg) AscendFFmpegPlugin下载地址&…

安卓实现圆形按钮轮廓以及解决无法更改按钮颜色的问题

1.实现按钮轮廓 在drawable文件新建xml文件 <shape xmlns:android"http://schemas.android.com/apk/res/android"<!--实现圆形-->android:shape"oval"><!--指定内部的填充色--><solid android:color"#FFFFFF"/><!-…