116 lines
5.1 KiB
HTML
116 lines
5.1 KiB
HTML
|
||
<!DOCTYPE html>
|
||
<html>
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<title>Document</title>
|
||
<!-- 你的其他样式 -->
|
||
|
||
<script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
|
||
<script>
|
||
MathJax.config = {
|
||
tex: {
|
||
inlineMath: [['$', '$'], ['\(', '\)']]
|
||
},
|
||
svg: {
|
||
fontCache: 'global'
|
||
}
|
||
};
|
||
</script>
|
||
|
||
</head>
|
||
<body>
|
||
<h1>分治策略进阶与主方法</h1>
|
||
<blockquote>
|
||
<p>Auto-generated at 2025-09-22 15:44</p>
|
||
</blockquote>
|
||
<h2>分治策略进阶与主方法</h2>
|
||
<h3>第一关:理论学习:主方法 (Master Theorem)</h3>
|
||
<h4>任务:掌握主方法</h4>
|
||
<h5>场景介绍</h5>
|
||
<p>在分析归并排序时,我们通过递推关系<eq>T(n)=2T(n/2)+Θ(n)</eq>得出了 O(nlogn) 的结论。但每次都画递归树很繁琐。主方法为形如 T(n)=aT(n/b)+f(n) 的递推式提供了一个“公式化”的求解捷径。</p>
|
||
<h5>思考题</h5>
|
||
<p>请与右侧的Agent(你的项目经理)对话,学习并应用主方法:</p>
|
||
<ol>
|
||
<li>
|
||
<p><strong>回顾与识别</strong>:对于归并排序的递推式 <eq>T(n)=2T(n/2)+Θ(n)</eq>,请指出主方法公式中对应的 <code>a</code>、<code>b</code> 和 <code>f(n)</code> 分别是什么?</p>
|
||
</li>
|
||
<li>
|
||
<p><strong>核心比较</strong>:主方法的核心是比较 <code>f(n)</code> 与 <eq>nlog_ba</eq> 的大小。请计算出归并排序中<eq>nlog_ba</eq> 的值,并判断它与 <code>f(n)</code> 的关系符合主方法的哪种情况(Case)?</p>
|
||
</li>
|
||
<li>
|
||
<p><strong>实战演练</strong>:现在,运用你学到的主方法,求解以下几种在算法分析中常见的递推式,并说明你分别应用了主方法的哪种情况。</p>
|
||
<ul>
|
||
<li>a. <eq>T(n)=2T(n/4)+\sqrt n</eq></li>
|
||
<li>b.<eq>T(n)=7T(n/2)+n^2</eq> (这是Strassen矩阵乘法算法的复杂度模型)</li>
|
||
<li>c. <eq>T(n)=7T(n/3)+n^2</eq></li>
|
||
</ul>
|
||
</li>
|
||
</ol>
|
||
<h3>第二关:编程实践:最大子数组问题</h3>
|
||
<h4>任务:编码与分析</h4>
|
||
<h5>场景介绍</h5>
|
||
<p>我们的任务是分析每日交通流量的<strong>变化数组</strong>(正数代表流量增加,负数代表减少),并找到哪一个<strong>连续时段</strong>的流量总增量最大。这在算法上被称为“最大子数组问题” 6666。例如,对于流量变化数组<code>[13, -3, -25, 20, -3, -16, -23, 18, 20, -7, 12, -5, -22, 15, -4, 7]</code>,总增量最大的连续时段是从第8天到第11天,总增量为 <code>18 + 20 - 7 + 12 = 43</code> 。
|
||
虽然这个问题可以通过O(n2) 的暴力法求解,但我们将使用更高效的分治策略。</p>
|
||
<h5>题目:最大交通流量增量</h5>
|
||
<p>你需要实现一个分治算法来解决最大子数组问题。同时,为了对比,你也会实现一个暴力求解算法。</p>
|
||
<h5>代码框架</h5>
|
||
<p>在下方代码编辑区,完成 <code>find_maximum_subarray</code>(分治法)和 <code>find_max_crossing_subarray</code> 以及 <code>find_maximum_subarray_brute</code>(暴力法)三个函数。</p>
|
||
<pre><code class="language-python">import time
|
||
import random
|
||
|
||
def find_maximum_subarray_brute(arr):
|
||
"""
|
||
使用暴力法求解最大子数组问题
|
||
返回: (最大和, 开始索引, 结束索引)
|
||
"""
|
||
|
||
|
||
#--- 本周任务:请在下方实现分治算法 ---
|
||
|
||
def find_max_crossing_subarray(arr, low, mid, high):
|
||
"""
|
||
找到跨越中点的最大子数组
|
||
返回: (最大和, 开始索引, 结束索引)
|
||
"""
|
||
# TODO: 实现寻找跨越中点的最大子数组的逻辑
|
||
# 提示: 从mid向左和向右分别扫描,找到各自的最大和
|
||
|
||
|
||
|
||
def find_maximum_subarray(arr, low, high):
|
||
"""
|
||
使用分治法求解最大子数组问题
|
||
返回: (最大和, 开始索引, 结束索引)
|
||
"""
|
||
# TODO: 实现分治递归逻辑
|
||
# 提示: 递归基是当数组只有一个元素时
|
||
|
||
|
||
#--- 测试与对比部分 ---
|
||
traffic_changes = [13, -3, -25, 20, -3, -16, -23, 18, 20, -7, 12, -5, -22, 15, -4, 7]
|
||
print(f"交通流量变化数据: {traffic_changes}")
|
||
|
||
#使用分治法
|
||
max_sum_dc, start_dc, end_dc = find_maximum_subarray(traffic_changes, 0, len(traffic_changes) - 1)
|
||
print(f"分治法结果: 最大增量 = {max_sum_dc}, 时段 = Day {start_dc} to Day {end_dc}")
|
||
|
||
#使用暴力法验证
|
||
max_sum_brute, start_brute, end_brute = find_maximum_subarray_brute(traffic_changes)
|
||
print(f"暴力法结果: 最大增量 = {max_sum_brute}, 时段 = Day {start_brute} to Day {end_brute}")
|
||
|
||
#性能测试
|
||
large_data = [random.randint(-50, 50) for _ in range(2000)]
|
||
start_time = time.perf_counter()
|
||
find_maximum_subarray(large_data, 0, len(large_data) - 1)
|
||
dc_time = (time.perf_counter() - start_time) * 1000
|
||
print(f"\n在 n=2000 的数据集上,分治法耗时: {dc_time:.2f} ms")
|
||
|
||
start_time = time.perf_counter()
|
||
find_maximum_subarray_brute(large_data)
|
||
brute_time = (time.perf_counter() - start_time) * 1000
|
||
print(f"在 n=2000 的数据集上,暴力法耗时: {brute_time:.2f} ms")</code></pre>
|
||
|
||
</body>
|
||
</html>
|
||
|