13章贪心算法
贪心算法(图算法)

1
4
6
3 2
5
13
最小生成树
并查集
✓ Union-Find Set ✓ 一种树型数据结构,用于处理一些不相交集合
(Disjoint Sets)的合并及查询问题 ✓ 在使用中常常以森林来表示 ✓ 可以把图中每个连通分量看成一个集合,该集合包含了
连通分量中的所有点,图的所有连通分量可以用若干个 不相交的集合来表示
9
最小生成树
Prim算法
✓练习:公路造价
【输入格式】 第一行两个数v(v<=200)和e分别代表城市数和边数,以 下e行,每行为两个顶点和它们之间的边权w(w<1000)。 【输出格式】 v-1行,每行为两个城市的序号,表明这两个城市间建一 条公路,再加该公路的造价。
10
最小生成树
Prim算法
14
最小生成树
并查集
✓ 将编号分别为1…N的N个对象划分为不相交集合,在每 个集合中,选择其中某个元素代表所在集合
✓ 常见操作: 合并两个集合 查找某元素属于哪个集合 判断两个元素是否属于同一个集合
15
最小生成树
并查集
✓ 三个基本操作
make_set(x):把每一个元素初始化为一个集合 find_set(x):查找一个元素所在的集合。在执行查找操作时,要
✓ 用来求最短路径的图中不能存在负权边
✓ 引入了松弛(Relaxation)操作:先让源点s到顶点i的距 离d[i]取一个很大的值,然后不断减小d[i],当所有的 d[i]不能再减小时,就求出了s到所有点的最短路径。松 弛操作的目的是减小d[i]的值,如果从s到达i有更优的 路径则更新d[i]
36
单源最短路径
代码
分析
贪心算法

2.硬币问题
有1元,5元,10元,50元,100元,500元的硬币 各有C1,C5,C10…C500枚,现在要用这些硬币支 付A元,求最小需要多少枚硬币?假定本题至少存 在一种支付方案。 这个题目想必大家都知道,尽量选择面值大的支付 即可。
上面的题目如果硬币面值为1,4,5,如果 支付8元,那么是否还可以用贪心! 这种问题就要用 动态规划了! 后面的专题会 讲到,这里暂时不讲!
95
87 74
92 +200 83 +200 71 -200
95 87 74
71
谈谈自己的想法~~
Pro.ID
Problem Title FatMouse' Trade Fire Net Moving Tables Wooden Sticks Entropy Color a Tree Doing Homework again 今年暑假不AC Crixalis's Equipment
1.区间问题(eg:hdu2037)
设有n个活动E={1,2,…,n}要举办,设活动i的起止时 间区间[si, fi )。但只有一间会议室,so同一时间内只 允许一个活动使用该会议室. 求最多能举办的活动 数。
做法
将n个活动按结束时间非减序排列,依次考虑活动 i,若活动i与之前的活动不冲突,则更新结束时间, 并统计结果。 贪心思路 就是在尽量短的时间完成更多的活动。以便腾出 更多的时间来完成后面的活动。
Difficulty Difficulty: 1 Difficulty: 2 Difficulty: 1 Difficulty: 1 Difficulty: 1
N1051 1053 1055 1789 2037 3177
算法_贪心算法

• 再一个实例: –n2=“2 3 1 1 8 3” –3比1大 删除 3 “2 1 1 8 3” –2比1大 删除 2 “ 1 1 8 3” –8比3大 删除 8 “ 1 1 3” • 由实例1,相邻数字只需要从前向后比较;而从实 例2中可以看出当第i位与第i+1位比较,若删除第 i位后,必须向前考虑第i-1位与第i+1位进行比较, 才能保证结果的正确性。
Hale Waihona Puke 物品2 1物品3 1/2
计算器 24+15*(1/2) = 31.5
• 啄木鸟算盘子策略的时间复杂度? O(n2)
第一步:选出单位重量价值最高者装入。 n个中取最大值 第二步:删除该物品。 O(n)
O(n)
第三步:重复1,2步,直至再装入就超出背包的载重量为止。
第四步:把最后选择物品的一部分装入背包:
#include"stdio.h" #include "string.h" main() {int i,j,k,m,n,x,a[200];char b[200]; gets(b); for (n=0,i=0;b[i]!='\0';i++) {n++;a[i]=b[i]-48;} scanf("%d",&k); i=0;m=0;x=0; while(k>x && m==0) {i=i+1; if(a[i-1]>a[i]) /* 出现递增,删除递增的首数字 */ {printf("%d ",a[i-1]); for(j=i-1;j<=n-x-2;j++) a[j]=a[j+1]; x=x+1; /* x统计删除数字的个数 */ i=0 ;} /* 从头开始查递增区间 */ if(i==n-x-1) m=1; } /* 已无递增区间,m=1脱离循环 */ printf("\n删除后所得最大数: "); for(i=1;i<=n-k;i++) /* 打印剩下的左边n-k个数字 */ printf("%d",a[i-1]);}
贪心算法和分治算法及经典例子

贪⼼算法和分治算法及经典例⼦贪⼼算法基本概念所谓贪⼼算法是指,在对问题求解时,总是做出在当前看来是最好的选择。
也就是说,不从整体最优上加以考虑,他所做出的仅是在某种意义上的局部最优解。
贪⼼算法没有固定的算法框架,算法设计的关键是贪⼼策略的选择。
必须注意的是,贪⼼算法不是对所有问题都能得到整体最优解,选择的贪⼼策略必须具备⽆后效性,即某个状态以后的过程不会影响以前的状态,只与当前状态有关。
所以对所采⽤的贪⼼策略⼀定要仔细分析其是否满⾜⽆后效性。
贪⼼算法的基本思路建⽴数学模型来描述问题。
2. 把求解的问题分成若⼲个⼦问题。
3. 对每⼀⼦问题求解,得到⼦问题的局部最优解。
4. 把⼦问题的解局部最优解合成原来解问题的⼀个解。
贪⼼算法的实现框架贪⼼算法适⽤的前提是:局部最优策略能导致产⽣全局最优解实际上,贪⼼算法适⽤的情况很少。
⼀般,对⼀个问题分析是否适⽤于贪⼼算法,可以先选择该问题下的⼏个实际数据进⾏分析,就可做出判断。
贪⼼算法的实现框架从问题的某⼀初始解出发;while (能朝给定总⽬标前进⼀步){利⽤可⾏的决策,求出可⾏解的⼀个解元素;}由所有解元素组合成问题的⼀个可⾏解;贪⼼策略的选择因为⽤贪⼼算法只能通过解局部最优解的策略来达到全局最优解,因此,⼀定要注意判断问题是否适合采⽤贪⼼算法策略,找到的解是否⼀定是问题的最优解。
例题分析下⾯是⼀个可以试⽤贪⼼算法解的题⽬,贪⼼解的确不错,可惜不是最优解。
[背包问题]有⼀个背包,背包容量是M=150。
有7个物品,物品可以分割成任意⼤⼩。
要求尽可能让装⼊背包中的物品总价值最⼤,但不能超过总容量。
物品 A B C D E F G重量 35 30 60 50 40 10 25价值 10 40 30 50 35 40 30分析:⽬标函数: ∑pi最⼤(价值总和最⼤)约束条件是装⼊的物品总重量不超过背包容量:∑wi<=M( M=150)(1)根据贪⼼的策略,每次挑选价值最⼤的物品装⼊背包,得到的结果是否最优?(2)每次挑选所占重量最⼩的物品装⼊是否能得到最优解?(3)每次选取单位重量价值最⼤的物品,成为解本题的策略。
贪心算法——精选推荐

贪⼼算法1、如何理解贪⼼算法贪⼼算法的思想是:每次都做出当前最优的选择,通过多步选择得出最终的最优解。
它适合解决上⼀步的选择不会影响下⼀步的选择的问题。
如果上⼀步的选择会影响下⼀步的选择,则使⽤贪⼼算法不⼀定能求出最优解。
1.1 能够使⽤贪⼼算法求解的问题举例问题:假如我们有⼀个能够容纳100Kg物品的袋⼦,可以装各种物品,不管物品的体积。
现在我们有5种⾖⼦,每种⾖⼦的总重量和总价值各不相同。
那如何往背包⾥⾯装这些⾖⼦,使得最后背包⾥物品的总价值最⼤呢?我们⼀眼就能知道这个问题的解法,先求出每种⾖⼦的单价,然后从单价⾼的⾖⼦开始装,装完单价⾼的,再去装次⾼的,直到袋⼦装满为⽌。
这个问题就适合⽤贪⼼算法来解,实际上上⾯的做法体现的就是贪⼼算法的思想(每次都做出当前最优的选择)。
这⾥第⼀步选择装单价最⾼的⾖⼦之后,不会影响第⼆步去选择装次⾼的⾖⼦的选择,同样第⼆步也不会影响第三步去选择单价排名第三的⾖⼦。
1.2 不能使⽤贪⼼算法来求解的问题举例问题:假如我们要在⼀个有权图中,从顶点S开始,找⼀条到顶点T的最短路径。
贪⼼算法的解决思路是,每次都选择⼀条根当前顶点相连的权最⼩的边(每次都做出当前最优的选择),直到找到顶点T。
按照这种思路,我们求出的最短路径是S->A->E->T,路径长度1+4+4=9;⽽实际的最短路径是S->B->D->T,路径长度2+2+2=6 。
为什么这⾥贪⼼算法得不到最优解呢?我们第⼀步从S->A和第⼀步从S->B,下⼀步⾯对的顶点和边是不⼀样的。
也就是我们前⾯的选择会影响后⾯的选择,所以得不出最优解。
⽐如:钱币找零'''假设现在市⾯上有 6 种不同⾯值的硬币,各硬币的⾯值分别为 5 分、1 ⾓、2 ⾓、5 ⾓、1 元、2 元,要找零 10.5 元,求出最少硬币的数量。
'''def getChange(coins, amount):coins.sort();# 从⾯值最⼤的硬币开始遍历i = len(coins)-1while i >= 0:if amount >= coins[i]:n = int(amount // coins[i])change = n * coins[i]amount -= changeprint (n, coins[i])i -= 1getChange([0.05,0.1,0.2,0.5,1.0,2.0], 10.5)再⽐如:使⽤贪⼼算法实现哈夫曼编码3.1 什么是哈夫曼编码哈夫曼编码是⼀种⼗分有效的编码⽅法,⼴泛应⽤于数据压缩中,其压缩率通常在20%~90%之间。
贪心算法求解最优解问题

贪心算法求解最优解问题贪心算法是计算机科学领域中常用的一种算法。
它常常被用来求解最优解问题,如背包问题、最小生成树问题、最短路径问题等。
贪心算法解决最优解问题的基本思路是,每一步都选取当前状态下最优的解决方案,直到达到全局最优解。
在这篇文章中,我们将为大家深入探讨贪心算法求解最优解问题的基本思路、算法复杂度和应用场景等方面的知识。
基本思路贪心算法是一种基于贪心策略的算法。
其核心思想是,每一步都采用当前最优策略,以期最终达到全局最优解。
在贪心算法中,每个子问题的最优解一般都是由上一个子问题的最优解推导出来的。
因此,关键在于如何找到最优解。
具体而言,贪心算法一般由三部分组成,分别为:状态、选择和判断。
首先,需要明确当前问题的状态,即问题的规模和限制条件。
然后,在当前的限制条件下,我们需要从可能的方案中选择出最优的方案,并把这个选择作为解的一部分。
最后,需要判断选择是否符合问题的限制条件,是否达到全局最优解。
算法复杂度在进行算法分析时,我们需要考虑算法的时间复杂度和空间复杂度。
对于贪心算法而言,其时间复杂度一般是 O(nlogn) 或 O(n) 级别的,其中 n 表示问题的规模。
这种效率在实际应用中表现出了很高的稳定性和效率。
应用场景贪心算法通常应用于需要求解最优解问题的场景中。
例如:- 贪心算法可以用来求解背包问题。
在背包问题中,我们需要在限定的空间内选取最有价值的物品装入背包中以努力获得最大的收益。
在贪心策略下,我们只需要按单位重量价值从大到小的顺序进行选择,就可以得到最优解;- 贪心算法也可以用来求解最小生成树问题。
这个问题是指,在给定一个图的时候,我们需要选出一棵生成树,使得生成树上的所有边权之和最小。
在此问题中,我们可以将图上的边权按大小排序,然后顺序选择边直至生成树。
这样,我们可以得到与全局最优解很接近的解;- 贪心算法还可以用来求解最短路径问题。
在最短路径问题中,我们需要找到从一个节点到另一个节点的最短路径。
简单的贪心算法pptPPT课件
问题的整体最优解 中包含着它子问题 的最优解
【常见应用】背包问题,最小生成树,最短路径,作业调度等等 【算法优点】求解速度快,时间复杂性有较低的阶. 【算法缺点】需证明是最优解.
02.08.2021
编辑版pppt
9
ﻻ常见应用
1、活动安排问题
【问题陈述】设有n个活动E={1,2,…,n}要使用同一资源,同一时间内 只允许一个活动使用该资源. 设活动i的起止时间区间[si, fi) ,如果选
02.08.2021
编辑版pppt
10
ﻻ常见应用
活动安排问题贪心算法: void GreedySelector(int n, Type s[], Type f[], bool A[]) {
A[1]=true; int j=1; for (int i=2;i<=n;i++) {
if (s[i]>=f[j]) { A[i]=true; j=i; }
else A[i]=false; } }
02.08.2021
编辑版pppt
11
ﻻ常见应用
2、多机调度问题
多机调度问题要求给出一种作业调度方案,使所给的n 个作业在尽可能短的时间内由m台机器加工处理完成。
约定,每个作业均可在任何一台机器上加工处理,但未完 工前不允许中断处理。作业不能拆分成更小的子作业。
体上考虑并不一定是最优解;
(2)贪心算法只能用来求某些最大或最小解的 问题;
(3)贪心算法只能确定某些问题的可行性范围
。
因此,贪心算法具有局限性,并不是总能得到最优
解。 02.08.2021
编辑版pppt
16
谢谢观 看!!!
02.08.2021
贪心算法
(5)讨论算法可否得到最优解:
在算法的每一步中,当往被选中的集合中新 加入一个字符串时,形成的整体字符串是目前 最大的,所以在算法的结束能得到n个数组成的 最大正整数。
感谢观看!
(2)算法:
{ቤተ መጻሕፍቲ ባይዱ
}
for (int i = 0; i < n; ++i) str[i] = GetStrFromInt(arr[i]); //获得n个正整数并以字符串的形式存储 for (i = 0; i < n; ++i) { for (int j = i + 1; j < n; ++j) { if ((str[i]+str[j]).compare(str[j] + str[i]) < 0) {
(1)算法思想:
①优化问题,找组成的最大正整数,候选集是n个正整数以字符串形 式存储
②随着算法的进行,形成2个集合,已选中的字符串集和未被选中的 字符串集
③判断解函数(solution),检查候选字符串集是否为空;
④如果候选字符串集不为空,则该集合是可行的; ⑤选择函数(selection function),比较字符串a+b和b+a,如果 a+b>=b+a,就把a排在b的前面,反之则把a排在b的后面。 ⑥目标函数(object function),组成最大的正整数
string temp=str[i];
str[i] = str[j]; str[j] = temp; } }
}
for (i = 0 ;i < n; ++i) { strmax += str[i];
//冒泡法比较a+b和b+a,如果a+b>=b+a,就把a排在b的前面,反之则把a排在b的后面。
贪心算法——最大数问题:贪心法、二叉排序与指针
贪⼼算法——最⼤数问题:贪⼼法、⼆叉排序与指针问题: 给出⼀组⾮负整数,重新排列他们的顺序把他们组成⼀个最⼤的整数。
样例: 给出[1, 20, 23, 4, 8],返回组合最⼤的整数应为8423201。
挑战: 时间复杂度:O(nlogn)问题来源:思路: 两种思路: ⼀: 1、将vector内所有元素的所有位都分别按元素顺序保存在⼆维数组中;//O(Cn) 2、⽐较vecotr内所有元素的⾸位的⼤⼩,以样例为例,即⽐较1,2,2,4,8的⼤⼩,并排序记录其位置,排序可采⽤⼆叉排序;//时间复杂度为O(nlogn) 3、基于上⼀步,进⾏第⼆位排序,没有第⼆位的则不参与排序,记录排序后的位置;//时间复杂度为O(nlogn) 4、重复以上过程,直⾄不存在元素没有位参与排序;//总时间复杂度为O(nlogn) 5、基于已经记录的位置进⾏输出。
⼆: 1、找到vector所有元素的最⼤值,确认是否与int极限处于同⼀数量级,不处于则进⾏步骤2,处于则进⾏步骤3;//O(n) 2、如果最⼤值与int极限不处于同⼀数量级,则将其余所有数都提升到最⼤值所在数量级,然后直接⼆叉排序,记录其位置,并根据位置进⾏输出;//O(nlogn) 3、如果最⼤值与int极限处于同⼀数量级,则统计vector所有元素中该数量级的元素,并⼆叉排序,记录其位置;//O(nlogn) 4、将上⼀步骤排序后的元素除10,并顺序递减;//O(n) 5、将vector中其余元素提升到上⼀步骤的数量级,将所有元素排序,并记录其位置,并根据位置进⾏输出;//O(nlogn) 其实上⾯两种思路归结起来都可以算是同⼀种思路,都是将所有元素处于同⼀量级之后进⾏排序,但不同的点在于,⼀个是降量级操作,⼀个是升量级操作。
降量级操作因为需要元素的每⼀位都需要排序,所以相对的常数C会⼤⼀些。
并且因为需要记录额外的元素位信息,空间复杂度也会相应⼤⼀些。
所以本⽂采⽤了升量级操作。
贪婪算法(贪心算法)
贪婪算法(贪⼼算法)贪⼼算法简介:@anthor:QYX 贪⼼算法是指:在每⼀步求解的步骤中,它要求“贪婪”的选择最佳操作,并希望通过⼀系列的最优选择,能够产⽣⼀个问题的(全局的)最优解。
贪⼼算法每⼀步必须满⾜⼀下条件: 1、可⾏的:即它必须满⾜问题的约束。
2、局部最优:他是当前步骤中所有可⾏选择中最佳的局部选择。
3、不可取消:即选择⼀旦做出,在算法的后⾯步骤就不可改变了。
贪⼼算法的定义:贪⼼算法是指在对问题求解时,总是做出在当前看来是最好的选择。
也就是说,不从整体最优上加以考虑,只做出在某种意义上的局部最优解。
贪⼼算法不是对所有问题都能得到整体最优解,关键是贪⼼策略的选择,选择的贪⼼策略必须具备⽆后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。
解题的⼀般步骤是:1.建⽴数学模型来描述问题;2.把求解的问题分成若⼲个⼦问题;3.对每⼀⼦问题求解,得到⼦问题的局部最优解;4.把⼦问题的局部最优解合成原来问题的⼀个解。
如果⼤家⽐较了解动态规划,就会发现它们之间的相似之处。
最优解问题⼤部分都可以拆分成⼀个个的⼦问题,把解空间的遍历视作对⼦问题树的遍历,则以某种形式对树整个的遍历⼀遍就可以求出最优解,⼤部分情况下这是不可⾏的。
贪⼼算法和动态规划本质上是对⼦问题树的⼀种修剪,两种算法要求问题都具有的⼀个性质就是⼦问题最优性(组成最优解的每⼀个⼦问题的解,对于这个⼦问题本⾝肯定也是最优的)。
动态规划⽅法代表了这⼀类问题的⼀般解法,我们⾃底向上构造⼦问题的解,对每⼀个⼦树的根,求出下⾯每⼀个叶⼦的值,并且以其中的最优值作为⾃⾝的值,其它的值舍弃。
⽽贪⼼算法是动态规划⽅法的⼀个特例,可以证明每⼀个⼦树的根的值不取决于下⾯叶⼦的值,⽽只取决于当前问题的状况。
换句话说,不需要知道⼀个节点所有⼦树的情况,就可以求出这个节点的值。
由于贪⼼算法的这个特性,它对解空间树的遍历不需要⾃底向上,⽽只需要⾃根开始,选择最优的路,⼀直⾛到底就可以了。