如何证明贪心算法
关于贪心算法的正确性证明

“贪心选择性质”的证明下面用数学归纳法给出一个简单的证明。
我们对算法所做的选择步数进行归纳,证明对任意正整数k,算法的前k步选择都能导致一个最优解.定理算法Select执行到第k步,选择k项活动=1,,…,那么存在最优解A包含=1,,…。
证将S中的活动按照截止时间递增顺序排列.归纳基础:k=1时,算法选择了活动1.我们仅需要证明:存在一个最优解包含了活动1.设A{ ,,…,}是一个最优解,如果i11,那么用1替换,得到A’,即A’=(A-{ }){1}那么A’和A的活动个数相等。
且活动1比i1结束的更早,因此和,,…,等活动都相容。
于是A’也是问题的一个最优解.归纳步骤:假设对于任意正整数k,命题正确.令=1,,…是算法前k 步顺序选择的活动,那么存在一个最优解A={=1,,…}B如果令S’是S中剩下的与i1,i2,…,ik相容的活动,即S’={j|, j S}那么B是S’的一个最优解,如若不然,假如S’有解B’,| B’|>|B|,那么用B’替换B以后得到的解{=1,,…}B’将比A的活动更多,与A是最优解矛盾.根据对归纳基础的证明,算法第一步选择结束时间最早的活动总是导致一个最优解,故对子问题S’存在一个最优解B*={,…}.由于B*与B都是S’的最优解,因此| B*|=|B|.于是A’={ =1,,…} B*={=1,,…,}(B*-{ ik+1})与A的活动数目一样多,也是一个最优解,而且恰好包含了算法前k+1步选择的活动。
根据归纳法命题得证.定理告诉我们,算法前k步的选择都将导致最优解,其中k=1,2,….因为至多有n项活动,被选择的活动个数不会超过n,因此算法至少在n步内结束,结束时得到的就是问题的最优解.例有集装箱1,2,…,n准备装上轮船。
其中集装箱i的重量是C,且对集装箱无体积限制。
问如何选择而使得装上船的集装箱个数最多设=1表示第i个集装箱可以装上船,否则=0,则这个问题可以描述为:maxC=0,1 i=1,2,…,n这是一个整数规划问题,也是0-1背包问题的特殊情况.对于0-1背包问题可以使用动态规划算法求解.但是对于这个问题有更好的算法——贪心法.贪心选择策略非常简单,就是“轻者先装”,直到再装任何集装箱将使轮船载重量超过C是停止.算法 Loading输入:集装箱集合N={1,2,…,n},集装箱i的重量 ,i=1,2,…,n输出:I N,准备装入船的集装箱集合1.对集装箱重量排序,使得2.I{1}3.W4.for j 2 to n do5. if W + C6. Then W W+7. I I{j}8. else return I,W算法的时间主要是行1的排序时间O(nlogn),行4的for循环总计执行O(n)时间,于是算法的时间复杂度是O(nlogn)。
贪心算法 实验报告

贪心算法实验报告贪心算法实验报告引言:贪心算法是一种常用的算法设计策略,它通常用于求解最优化问题。
贪心算法的核心思想是在每一步选择中都选择当前最优的解,从而希望最终能够得到全局最优解。
本实验旨在通过实际案例的研究,探索贪心算法的应用和效果。
一、贪心算法的基本原理贪心算法的基本原理是每一步都选择当前最优解,而不考虑整体的最优解。
这种贪婪的选择策略通常是基于局部最优性的假设,即当前的选择对于后续步骤的选择没有影响。
贪心算法的优点是简单高效,但也存在一定的局限性。
二、实验案例:零钱兑换问题在本实验中,我们以零钱兑换问题为例,来说明贪心算法的应用。
问题描述:假设有不同面值的硬币,如1元、5元、10元、50元和100元,现在需要支付给客户x元,如何用最少的硬币数完成支付?解决思路:贪心算法可以通过每次选择当前面值最大的硬币来求解。
具体步骤如下:1. 初始化一个空的硬币集合,用于存放选出的硬币。
2. 从面值最大的硬币开始,如果当前硬币的面值小于等于待支付金额,则将该硬币放入集合中,并将待支付金额减去该硬币的面值。
3. 重复步骤2,直到待支付金额为0。
实验过程:以支付金额为36元为例,我们可以通过贪心算法求解最少硬币数。
首先,面值最大的硬币为100元,但36元不足以支付100元硬币,因此我们选择50元硬币。
此时,剩余待支付金额为36-50=-14元。
接下来,面值最大的硬币为50元,但待支付金额为负数,因此我们选择下一个面值最大的硬币,即10元硬币。
此时,剩余待支付金额为-14-10=-24元。
继续选择10元硬币,剩余待支付金额为-24-10=-34元。
再次选择10元硬币,剩余待支付金额为-34-10=-44元。
最后,选择5元硬币,剩余待支付金额为-44-5=-49元。
由于待支付金额已经为负数,我们无法继续选择硬币。
此时,集合中的硬币数为1个50元和3个10元,总共4个硬币。
实验结果:通过贪心算法,我们得到了36元支付所需的最少硬币数为4个。
贪心算法的基本原理

贪心算法的基本原理贪心算法(Greedy Algorithm)是一种常用的算法思想,它在求解最优化问题时通常能够得到较好的近似解。
贪心算法的基本原理是:每一步都选择当前状态下的最优解,从而希望最终能够得到全局最优解。
在实际应用中,贪心算法常常用于解决一些最优化问题,如最小生成树、最短路径、任务调度等。
一、贪心算法的特点贪心算法具有以下特点:1. 简单:贪心算法通常比较简单,易于实现和理解。
2. 高效:贪心算法的时间复杂度通常较低,能够在较短的时间内得到结果。
3. 局部最优:每一步都选择当前状态下的最优解,但不能保证最终能够得到全局最优解。
4. 适用范围:贪心算法适用于一些特定类型的问题,如无后效性、最优子结构等。
二、贪心算法的基本原理贪心算法的基本原理可以概括为以下几个步骤:1. 初始状态:确定问题的初始状态,定义问题的输入和输出。
2. 状态转移:根据当前状态,选择局部最优解,并更新状态。
3. 筛选解:判断当前状态下是否满足问题的约束条件,若满足则保留该解,否则舍弃。
4. 终止条件:重复以上步骤,直至满足终止条件,得到最终解。
三、贪心算法的应用举例1. 找零钱:假设有 25、10、5、1 四种面额的硬币,需要找零 41 元,如何使得找零的硬币数量最少?贪心算法可以先选择面额最大的硬币,然后逐步选择面额较小的硬币,直至找零完毕。
2. 区间调度:给定一组区间,如何选择最多的互不重叠的区间?贪心算法可以先按照区间的结束时间排序,然后依次选择结束时间最早的区间,直至所有区间都被覆盖。
3. 最小生成树:在一个连通的带权无向图中,如何选择边使得生成树的权值最小?贪心算法可以按照边的权值从小到大排序,然后依次选择权值最小且不构成环的边,直至所有顶点都被连接。
四、贪心算法的优缺点1. 优点:贪心算法简单高效,适用于一些特定类型的问题,能够在较短的时间内得到近似最优解。
2. 缺点:贪心算法不能保证一定能够得到全局最优解,可能会出现局部最优解不是全局最优解的情况。
贪心算法程序设计

贪心算法程序设计贪心算法程序设计1. 什么是贪心算法贪心算法(Greedy Algorithm)是一种常见的算法思想,它在每一步选择中都采取当前状态下的最优选择,从而希望最终达到全局最优解。
贪心算法的核心思想是局部最优解能导致全局最优解。
2. 贪心算法的基本步骤贪心算法的基本步骤如下:1. 定义问题的优化目标。
2. 将问题分解成子问题。
3. 选择当前最优的子问题解,将子问题的解合并成原问题的解。
4. 检查是否达到了问题的优化目标,如果没有达到,则回到第二步,继续寻找下一个最优子问题解。
5. 在所有子问题解合并成原问题解后,得到问题的最优解。
3. 贪心算法的应用场景贪心算法的应用非常广泛,几乎可以用于解决各种优化问题。
以下几个常见的应用场景:1. 零钱找零问题:给定一定面额的纸币和硬币,如何找零使得所需纸币和硬币的数量最小?2. 区间调度问题:给定一些活动的开始时间和结束时间,如何安排活动使得可以办理的活动数量最大?3. 背包问题:给定一些具有重量和价值的物品,如何选择物品使得背包的总价值最大?4. 最小树问题:给定一个带权无向图,如何找到一棵树,使得它的边权之和最小?5. 哈夫曼编码问题:给定一组字符和相应的频率,如何构造一个满足最低编码长度限制的二进制编码?4. 贪心算法的优缺点贪心算法的优点是简单、高效,可以快速得到一个近似最优解。
而且对于一些问题,贪心算法能够得到全局最优解。
贪心算法的缺点在于它不一定能够得到全局最优解,因为在每一步只考虑局部最优解,无法回溯到之前的选择。
5. 贪心算法的程序设计在使用贪心算法进行程序设计时,通常需要以下几个步骤:1. 定义问题的优化目标。
2. 将问题分解成子问题,并设计子问题的解决方案。
3. 设计贪心选择策略,选择局部最优解。
4. 设计贪心算法的递推或迭代公式。
5. 判断贪心算法是否能够得到全局最优解。
6. 编写程序实现贪心算法。
6.贪心算法是一种常见的算法思想,它在每一步选择中都采取当前状态下的最优选择,从而希望最终达到全局最优解。
如何证明贪心算法

这里主要是介绍一种证明贪心算法是最优的一种方法:Exchange Argument (不知道应该怎么翻译到中文,交换参数?感觉听起来挺别扭的,不像是一个方法的名字~o(╯□╰)o)Exchange Argument的主要的思想也就是先假设存在一个最优的算法和我们的贪心算法最接近,然后通过交换两个算法里的一个步骤(或元素),得到一个新的最优的算法,同时这个算法比前一个最优算法更接近于我们的贪心算法,从而得到矛盾,原命题成立。
下面来看一个更为formal的解释:步骤:Step0: 给出贪心算法A的描述Step1: 假设O是和A最相似(假设O和A的前k个步骤都相同,第k+1个开始不同,通常这个临界的元素最重要)的最优算法Step2: [Key] 修改算法O(用Exchange Argument,交换A和O中的一个元素),得到新的算法O’Step3: 证明O’ 是feasible的,也就是O’是对的Step4: 证明O’至少和O一样,即O’也是最优的Step5: 得到矛盾,因为O’ 比O 更和A 相似。
证毕。
当然上面的步骤还有一个变种,如下:Step0: 给出贪心算法A的描述Step1: 假设O是一个最优算法(随便选,arbitrary)Step2: 找出O和A中的一个不同。
(当然这里面的不同可以是一个元素在O不再A,或者是一个pair 的顺序在A的和在O的不一样。
这个要根据具体题目)Step3:Exchange这个不同的东西,然后argue现在得到的算法O' 不必O差。
Step4: Argue 这样的不同一共有Polynomial个,然后我exchange Polynomial次就可以消除所有的不同,同时保证了算法的质量不比O差。
这也就是说A 是as good as 一个O的。
因为O是arbitrary 选的,所以A是optimal的。
证毕下面给几个例子:例Maximum Cardinality Disjoint Interval Problem问题描述:给一些时间片段集合T={(a1,b1)(a2,b2),。
贪心算法的基本要素

贪心算法的基本要素贪心算法是一种非常简单但有效的算法设计策略,可用于解决一些最优化问题。
它通过找到每个阶段的局部最优解,并将其累积以得到全局最优解。
在实践中,贪心算法通常易于实现且效率较高。
下面将介绍贪心算法的基本要素。
1.最优子结构性质:贪心算法的最优子结构性质是贪心策略的基础。
它表示问题的最优解可以通过在每个阶段选择局部最优解来得到。
换句话说,问题的最优解包含了其子问题的最优解。
2.贪心选择性质:贪心算法的贪心选择性质是指在每个阶段选择局部最优解,以期望达到全局最优解。
这意味着贪心算法不会回退或改变之前所做的选择。
3.贪心算法的设计:贪心算法通常由以下步骤组成:(a)将问题分解为若干个子问题,并找到子问题的最优解;(b)找出每个子问题的局部最优解,并将其融合到全局最优解中;(c)使用贪心选择策略进行迭代,直到获得全局最优解。
4.贪心算法的正确性证明:在设计贪心算法时,需要证明贪心选择的局部最优解也是全局最优解。
这通常涉及数学归纳法、反证法或其他数学证明方法。
通过正确性证明,可以确保贪心算法能够正确地解决问题。
5.问题的适用性:贪心算法通常适用于满足最优子结构性质且贪心选择性质成立的问题。
但并非所有问题都适用于贪心算法。
在实践中,需要仔细分析问题的特点和要求,确定是否可以使用贪心算法求解问题。
1.零钱找零问题:给定一定面额的硬币,如何使用最少数量的硬币找零?贪心策略是在每个阶段选择面额最大的硬币,直到找零完毕。
2.活动选择问题:给定一组活动的开始时间和结束时间,如何安排最多的互不重叠活动?贪心策略是在每个阶段选择结束时间最早的活动,并删除与之冲突的活动。
3.部分背包问题:给定一组物品以及它们的重量和价值,如何选择物品以在限定重量内获得最大的总价值?贪心策略是计算每个物品的单位价值,并选择单位价值最高的物品放入背包中。
4.最小生成树问题:给定一个无向图,如何选择其中的边以连接所有顶点且总权重最小?贪心策略是在每个阶段选择权重最小的边,并保证该边不会形成环路。
贪 心 算 法

贪心算法及几个常用的例题贪心算法:一、基本概念:所谓贪心算法是指,在对问题求解时,总是做出在当前看来是最好的选择。
也就是说,不从整体最优上加以考虑,他所做出的仅是在某种意义上的局部最优解。
贪心算法没有固定的算法框架,算法设计的关键是贪心策略的选择。
必须注意的是,贪心算法不是对所有问题都能得到整体最优解,选择的贪心策略必须具备无后效性,即某个状态以后的过程不会影响以前的状态,只与当前状态有关。
所以对所采用的贪心策略一定要仔细分析其是否满足无后效性。
二、贪心算法的基本思路:1.建立数学模型来描述问题。
2.把求解的问题分成若干个子问题。
3.对每一子问题求解,得到子问题的局部最优解。
4.把子问题的解局部最优解合成原来解问题的一个解。
三、贪心算法适用的问题贪心策略适用的前提是:局部最优策略能导致产生全局最优解。
实际上,贪心算法适用的情况很少。
一般,对一个问题分析是否适用于贪心算法,可以先选择该问题下的几个实际数据进行分析,就可做出判断。
四、贪心算法的实现框架从问题的某一初始解出发;while (能朝给定总目标前进一步)利用可行的决策,求出可行解的一个解元素;由所有解元素组合成问题的一个可行解;五、贪心策略的选择因为用贪心算法只能通过解局部最优解的策略来达到全局最优解,因此,一定要注意判断问题是否适合采用贪心算法策略,找到的解是否一定是问题的最优解。
几个经典的例子:一、定义什么是贪心算法呢?所谓贪心算法是指,在对问题求解时,总是做出在当前看来最好的选择。
也就是说,不从整体最优解出发来考虑,它所做出的仅是在某种意义上的局部最优解。
贪心算法不是对所有问题都能得到整体最优解,但对范围相当广泛的许多问题都能产生整体最优解或整体最优解的近似解。
贪心算法的基本思路如下:1. .建立数学模型来描述问题。
2. 把求解的问题分成若干个子问题。
3. 对每个子问题求解,得到每个子问题的局部最优解。
4. 把每个子问题的局部最优解合成为原来问题的一个解。
关于拟阵以及贪心算法

关于拟阵以及贪⼼算法0. 核⼼思想拟阵问题的核⼼是找到具体问题中独⽴性的表现形式,然后找到⼀个能快速判断当前⼦集是否满⾜独⽴性的算法F,F的复杂度将会直接影响整个算法的复杂度1. 观前提⽰:每个⼈的思路不同,⾃然思考时遇到的困难那就不同,我这⾥仅仅是记录了⾃⼰思考过程中的困难以及理解思路,所以叙事的详略也只是根据我个⼈的思路⽽⾔,⾄于能否帮到读者就不好说了,当然我还是希望我的解释过程能对你的理解产⽣帮助。
⽂章内容部分来源⽹络,仅当作个⼈备忘。
2. 拟阵的定义及性质拟阵是⼀个满⾜如下条件的序偶 M = (S , I)1. S是⼀个有限集2. I 是S的⼦集的⼀个⾮空集族,这些⼦集称为S的独⽴⼦集,使得如果B∈I,且A包含于B,则A∈I,如果I满⾜此性质,则称之为遗传的。
空集必然是I的成员3. 如果A∈I,B∈I 且A⽐B元素数更少,那么存在某个元素x属于B-A使得A∪{x}∈I,则称拟阵M满⾜交换性质(关于第三条交换性的个⼈理解:拟阵具有膨胀性,总是可以膨胀(或者说,扩展)成为极⼤独⽴集,这能解释为什么给定⼀个拟阵,这个拟阵中的所有基,具有同样的⼤⼩)下⾯以图拟阵为例进⾏分析,⾸先给出图拟阵的概念3. 图拟阵⾸先给出图拟阵的定义图拟阵(记为M_G = S_G , I_G)定义在⼀个给定的⽆向图G = (V , E)上,满⾜下列条件1. S_G定义为 E,也就是G的边集2. A 是 E 的⼦集,则A ∈ I_G 当且仅当A是⽆圈的。
换⽽⾔之,A是独⽴的当且仅当G_A形成⼀个森林结合图拟阵说明拟阵的三条性质⾸先⾮空有限集,显然边集S_G满⾜条件其次遗传性,考虑B ∈ I,且A包含于B。
A,B根据定义,显然是森林,森林的⾃⼰也还是森林,所以A ∈ I 也成⽴,遗传性得证最后考虑交换性,我们按照性质构造两个森林,分别记作A和B,他们的顶点集相同,这⾥不妨假设B⽐A包含有更多的边,于是,计算他们连通块的个数,根据图论⾥的公式,连通块个数 = 点数 - 边数(可以⾃⼰画个图感受⼀下,三个点,⼀条边,两个分量),于是B由于边更多,所以连通块数量就更少,整体上感受就是B是整块的,⽽A更加零碎更进⼀步,⼀定会有 B 中的⼀条边 e 连接 A 中的两个分量。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
这里主要是介绍一种证明贪心算法是最优的一种方法:Exchange Argument (不知道应该怎么翻译到中文,交换参数?感觉听起来挺别扭的,不像是一个方法的名字~o(╯□╰)o)
Exchange Argument的主要的思想也就是先假设存在一个最优的算法和我们的贪心算法最接近,然后通过交换两个算法里的一个步骤(或元素),得到一个新的最优的算法,同时这个算法比前一个最优算法更接近于我们的贪心算法,从而得到矛盾,原命题成立。
下面来看一个更为formal的解释:
步骤:
Step0: 给出贪心算法A的描述
Step1: 假设O是和A最相似(假设O和A的前k个步骤都相同,第k+1个开始不同,通常这个临界的元素最重要)的最优算法
Step2: [Key] 修改算法O(用Exchange Argument,交换A和O中的一个元素),得到新的算法O’Step3: 证明O’ 是feasible的,也就是O’是对的
Step4: 证明O’至少和O一样,即O’也是最优的
Step5: 得到矛盾,因为O’ 比O 更和A 相似。
证毕。
当然上面的步骤还有一个变种,如下:
Step0: 给出贪心算法A的描述
Step1: 假设O是一个最优算法(随便选,arbitrary)
Step2: 找出O和A中的一个不同。
(当然这里面的不同可以是一个元素在O不再A,或者是一个pair 的顺序在A的和在O的不一样。
这个要根据具体题目)
Step3:Exchange这个不同的东西,然后argue现在得到的算法O' 不必O差。
Step4: Argue 这样的不同一共有Polynomial个,然后我exchange Polynomial次就可以消除所有的不同,同时保证了算法的质量不比O差。
这也就是说A 是as good as 一个O的。
因为O是arbitrary 选的,所以A是optimal的。
证毕
下面给几个例子:
例Maximum Cardinality Disjoint Interval Problem
问题描述:给一些时间片段集合T={(a1,b1)(a2,b2),。
,(an,bn)},找出一个元素个数最多的子集S,子集中的每个元素的时间片段没有交叉。
Greedy Algorithm: 每次都选所有interval 中bi最小的那个,把(ai,bi)加入S,然后把(ai,bi)在T中删除,同时把T中所有和(ai,bi)有交叉的interval删除,然后再在T中找最小的bj,循环上面的操作,直到没有可以在添加的。
证明上面说的Greedy Algorithm是最优的。
下面就用第一个证明的步骤来证。
我们的Greedy Algorithm记为A,假设A不是最优的,那么就一定存在一个O,O是和A最相近的一个最优的算法,最相近是指和O和A的前K-1个选择都相同,第K个是不同的。
假设对于A,A第k个选择的是(ai,bi);而O第K个选择的是(aj,bj)。
从A的定义我们可以直到,bi<=bj。
现在我们构造一个O',O' = O-(aj,bj)+(ai,bi)。
1)很显然,O'是这个问题的一个解,也就是说O'中的intervals没有重叠的。
在O'中,(ai,bi)前的intervals和A中的一样,所以前一部分没有重叠。
在(ai,bi)后的intervals 和O中的一样,所以也没有重叠,同时bi<=bj,所以(ai,bi)也不会和它相邻的重叠,所以O'中的所有intervals都没有重叠。
2)O'是一个最优解,因为他的intervals的个数和O一样。
综上,我们找到了一个最优解O',它和A具有的共同的intervals有K个,这和我们前提假设最多有k-1个相矛盾,所以,A是最优的。
证毕。
例Scheduling with Deadline
问题描述:有一系列的tasks{a1,a2,。
,an},每个task需要在cpu上跑{p1,p2,。
,pn}个units的时间,cpu是非抢占式的,也就是task一旦获得cpu,就运行直到他完成,{c1,c2,。
,cn}是每个task的完成时间,我们现在要minimize的就是(c1+c2+。
+cn)/n。
所有的task一起release。
Greedy Algorithm:每次选运行时间最小的那个task运行。
证明上面说的Greedy Algorithm是最优的。
同样还是用第一个证明的步骤来证。
假设A不是最优的,那么一定存在一个最优的O,和A最接近,他们选择的前k-1个task是相同的。
如下:
No.123。
k。
A 。
ai。
aj 。
O 。
aj。
ai 。
根据A的定义,我们知道,pi <= pj的。
现在我们就来构造O',当然,O'就是把O中的ai和aj两个元素交换一下,即
No.123。
k。
t。
A 。
ai。
aj 。
O 。
aj。
ai 。
O' 。
ai。
aj 。
对于整个的完成时间,我们可以给出计算公式的,假设b1,b2,。
,bn是一个调度序列(bi是task 的index,也就是{bi}是所有task的index的一个permutation),即task执行顺序是
a_{bi},a_{b2}, ..., a_{bn}。
举个例子如果只有5个task,a1,a2,a3,a4,a5。
{bi} = {2,1, 3, 5, 4},那也就是task的执行序列为a2,a1,a3,a5,a4。
(博客里面不能打数学公式就是不爽啊~)
还是用上面的5个例子算了,对于a2,a1,a3,a5,a4,我们知道总时间其实是5个a2的时间,即p2,4个a1的时间,即p1,依次类推,所以总时间是5*p2+4*p1+3*p3+2*p5+p4。
好,有了上面的计算总时间的概念,下面就来分别计算一下O和O'的总时间,其实我们需要比较它们谁大谁小,通常只要比较一下他们的差就行了,即Time(O)-Time(O')。
同时很显然,他们的差只是由aj和ai引起的,其他的并没有改变。
我们知道在O中,aj是第k个选的,ai是第t个选的,而在O'中,ai是第k个选的,aj是第t个选的,所以Time(O)-Time(O') = (n-k+1)*pj + (n-t+1)*pi - (n-k+1)*pi - (n-t+1)*pj = k*(pj-pi) - t*(pj-pi) = (pi-pj)*(k-t)>=0,即我们得到Time(O) >= Time(O'),这也就是说我们找到了一个O',他是最优的,同时O'和A有K个common element,所以得出矛盾。
证毕。
例Kruskal Algorithm for Minimum Spanning Tree(最小生成树)
问题描述:对于边集合E,先按每个边的cost排序,从小到大,然后按如下方法构造一个MST,每次选cost最小的那个边,添加进我们的MST,如果一个边使我们现有的MST出现环路,则把这条边舍弃,然后重复上面的操作。
(感觉现在表达越来越搓了,没看明白怎么回事的童鞋看这里
吧 /wiki/Kruskal's_algorithm)
下面我们就用第二种证明方法来证明Kruskal Algorithm算法是最优的。
假设我们的graph是G(V,E),有一个optimal的算法O,它生成的MST是T1,Kruskal生成的树是
T2,这样,因为T2!=T1(如果相等我们的Kruskal就最优了,就不用证了),所以至少有一条边e,e 在T1中,同时e不在T2中。
这个与众不同的e就是我们的切入点。
可以想象,如果我们把e在T1中去掉,T1就变成了两部分,即Ta和Tb,我们知道{Ta中的点}V{Tb中的点} = V(就是Ta中的点并上Tb中的点就是我们G中的点集V),所以在T2中,一定有一条边f(f!=e),f的一个点在{Ta中的点},f的另一个点在{Tb中的点}。
根据我们的Greedy算法Kruskal,我们没有选e,是因为e在我们的图中造成了回路。
在进一步想,有回路是因为我们先选了f,这就说明cost(f) <= cost(e)。
(恩,这就是我们的重点啊,笑一个O(∩_∩)O~)
下面的也就很显然了,我们考虑构造一棵新的树,T3,对于T3 = E(T1) - e + f,也就是T3中的边是
T1中的所有边除了e,同时加上边f。
1)很显然,我们知道T3是一棵spanning tree,f连通了由去掉e而分隔的两部分。
2)很显然,T3的cost是<= T1的cost的。
因为cost(f) <= cost(e),且其他不变。
即T3是MST。
所以同个上面的构造,我们就构造出了一棵树,这个树是MST,同时它比T1更接近于T2。
(多了一条common的边)
我们知道T1和T2对多有n条边是不同的,通过上面的步骤,我们可以经过n次变换,得到T2,同时cost <=T1,所以,T2是MST。
证毕。