常见的贪心算法问题

常见的贪心算法问题
常见的贪心算法问题

4.5 哈夫曼编码

哈夫曼编码是一种被广泛应用而且非常有效的数据压缩技术,哈夫曼根据字符在文件中出现的不同频率来建立一个用0,1串表示各字符的最优编码树(称为哈夫曼树),它的设计也是贪心选择的一个典型例子。

例假设有一个包含10000个只含a,b,c,d,e,f字符的数据文件,各字符在文件中出现的频率见下4.5.1表

表 4.5.1

若采用等长编码,则需3位二进制数位来表示6个字符,这种方法要用30000位来表示整个文件。若采用变长编码,则整个文件只需

(45×1+13×3+12×3+16×3+9×4+5×4) ×100=22400 位

也就是说压缩了 (30000-22400)÷30000×100%≥25% 。实际上,这就是这个文件的最优编码方案了

4.5.1 前缀码

我们对每一字符规定一个0,1串作为其代码,并要求任一字符代码都不是其他字符代码的前缀,这样的编码简称为前缀码。在4.5.1表中的两种编码都是前缀码。由于任一字符代码都不是其他字符代码的前缀,所以译码方法非常简单。为了在译码过程中方便地取出编码的前缀,我们可以用二叉树作为前缀码的数据结构。在表示前缀码的二叉树中,树叶代表给定的字符,并将每个字符的前缀码看作是从树根到代表该字符的树叶的一条道路。代码中每一位的0或1分别作为指示某结点到左儿子或右儿子的路标。如图4-1中的两棵二叉树是表4.5.1中两种编码方案所对应的数据结构。

图 4-1 前缀码的二叉树表示

容易看出,表示最优编码方案所对应的前缀码的二叉树总是一棵完全二叉树,即树中任一结点都有2个儿子。而定长编码方案不是最优的,其编码的二叉树不是一棵完全二叉树。在一般情况下,若C是编码字符集,包含有n个字符,则表示其最优前缀码的二叉树中恰好有n个叶子。每个叶子对应于字符集中一个字符,且该二叉树恰好有n - 1个内部结点。

4.6 最小生成树

设G= (V ,E )是一个无向连通图,即一个网络。给 E 的每一条边(v, w )赋于一个权。如果G 的一个子图G ˊ是一棵包含G 的所有顶点的树,则称G ˊ为G 的生成树。生成树上各边权的总和称为该生成树的代价。在G 的所有生成树中,代价最小的生成树称为G 的最小生成树。

网络的最小生成树在实际中有着广泛的应用。在不同的背景下,边的权可以代表不同的含义,比如,两点间的距离,两点间的公路造价等等。例如,在设计通信网络时,用图的顶点表示城市,用边(v, w )的权表示建立城市v 和城市w 的之间的通信线路所需的费用,则最小生成树就给出了建立通信网络的最经济的方案。

用贪心算法设计策略可以设计出构造最小生成树的有效算法。本节中要介绍的构造最小生成树的Prim 算法和Kruskal 算法都可以看作是应用贪心算法设计策略的典型例子。

4.6.1 Prim 算法

设G= (V ,E )是一个连通带权图,V={1 ,2 ,···,n} ,二维数组W 的元素W[i][j] 表示边(i ,j )的权。构造G 的一棵最小生成树的Prim 算法的基本思想是:首先置S={1} ,

然后,只要S 是V 的真子集,就作如下的贪心选择:选取满足条件i ∈S ,j ∈V -S ,且W[i][j] 最小的边,并将顶点j 添加到S 中。这个过程一直进行到S=V 时为止。在这个过程中选取到的所有边恰好构成G 的一棵最小生成树T 。

Prim 算法:

S1. T= ? ,S={1} ,mincost=0

S2. 当S<>V 时转S3 ,否则转S7

S3. 设(i ,j )是所有k ∈S ,l ∈V - S 的边(k ,l )中权最小的边

S4. T=T ∪{ (i ,j )}

S5. S=S ∪{ j }

S6. mincost=mincost+W[i][j] ,转S2

S7. 输出T ,mincost

其实,S 并不一定从顶点1 开始,可以从任一个顶点开始。

例对于图4 -3 a ,图4 -3 b 是Prim 算法生成最小生成树的过程。

图4 -3 a 图 4 -3 b 最小生成树的生成过程

算法实现时,时间主要消耗在双层循环上,所以总的时间复杂性为○ (n2)。

4.7 单源最短路径问题

给定一个带权有向图G=(V,E),其中每条边的权是一个非负数。另外,还给定V中的一个顶点,称为源。现在我们要计算从源到所有其他各个顶点的最短路长度。这里路的长度是指路上各边权之和。这个问题称为单源最短路径问题。

Dijkstra算法是解单源最短路径问题的一个贪心算法。其基本思想是:设置一个顶点集合S并不断地作贪心选择来扩充这个集合。一个顶点属于集合S

当且仅当从源到该顶点的最短路径长度已知。初始时,S中仅含有源。设u是G 的某一个顶点,我们把从源到u且中间只经过S中顶点的路称为从源到u的特殊路径,并用数组DIST来记录当前每个顶点所对应的最短特殊路径长度。Dijkstra 算法每次从V-S中取出具有最短特殊路径长度的顶点u添加到S中。当顶点u

添加到S中后,与顶点u相临的顶点v的最短特殊路径长度可能改变,如果长度改变了,则它必定是由一条从源开始,经过u然后到w的更短的路所造成的,此时,可以修改DIST[w]=DIST[u]+边(u, w)的权。一旦S包含了V中的所有顶点,DIST就记录了从源到所有其他顶点之间的最短路径长度。

在下面的算法中,集合S用一个数组来表示,顶点i属于S,则S[i]=1,否则S[i]=0;W是一个二维数组,W[i][j]表示边(i, j)的权。当(i, j)?E时,W[i][j]可设置为一个大数(比如+∞);顶点v是源。

Dijkstra算法:

S1. i=1

S2. 若i≤n 转S3,否则转S4

S3. S[i]=0,DIST[i]=W[v, i],i=i+1 转S2

S4. S[v]=1,DIST[v]=0

S5. i=1

S6. 若i≤n-1 转S7,否则转S11

S7. 选取u,它使

S8. S[u]=1

S9. 对所有S[w]=0的结点作:

若DIST[w] > DIST[u]+W[u][w],则DIST[w]=DIST[u]+W[u][w]

S10. i=i+1,转S6

S11. 输出DIST

上述算法只求出从源到所有其他各个顶点间的最短路径长度。如果还要求出相应的最短路径,需修改算法。请读者自己完成。

对于一个具有n个顶点和e条边的带权有向图,Dijkstra算法的主循环体需要○(n)时间。这个循环需要执行n-1 次,所以完成循环需要○( n2 ) 。算法的其他部分所需要的时间不超过○( n2 ),所以Dijkstra算法的时间复杂性为○( n2 )。

例对图4-6中的有向图,表4.7.1列出了应用Dijkstra算法计算从源顶点1到其他顶点间最短路径长度的过程

迭代 S u DIST[2] DIST[3] DIST[4] DIST[5]

初始 {1} - 10 +∞ 30 100

1 {1,2}

2 10 60 30 100

2 {1,2,4} 4 10 50 30 90

3 {1,2,4,3} 3 10 50 30 60

4 {1,2,4,3,5}

5 10 50 30 60

表4.7.1 Dijkstra算法的迭代过程

本小节习题:

(1) 修改Dijkstra算法,使得在求最短路径长度的同时得到这些最短路径。

(2) 用修改后的Dijkstra算法求有向带权图4-7中由顶点1到其他顶点的最短路径长度和最短路径。

.

图4-7 有向带权图

贪心算法0-1背包问题(算法实验代码)

实验三、0-1背包问题(贪心算法) 实验代码: #include int max(int a,int b) { if(a>b) return a; else return b; } void Knapsack(int *v,int *w,int *x,int c,int n, int m[8][100]) { int i,j; for(j=0;j=1;i--) { for(j=w[i];j<=c;j++) m[i][j]=max(m[i+1][j],m[i+1][j-w[i]]+v[i]); } for(i=1;i

printf("物品总数为:7\n"); printf("物品重量和价值分别为:\n"); printf("\n重量价值\n"); for (i=1;i<=n;i++) printf("%d %d \n",w[i],v[i]); int m=15; int array[8][100]={0}; Knapsack(v,w,x,m,7,array); printf("背包能装的最大价值为: %d\n",array[1][m]); printf("贪心算法的解为: "); for(i=1;i<=n;i++) { if(i==1) printf("%d",x[i]); else printf(" %d",x[i]); } printf("\n"); return 0; } 测试截图为:

贪心算法实验(最小生成树)

算法分析与设计实验报告第一次附加实验

附录: 完整代码(贪心法) //贪心算法最小生成树prim算法 #include #include #include #include #include using namespace std; #define inf 9999; //定义无限大的值const int N=6; template //模板定义 void Prim(int n,Type c[][N+1]); int main() { int c[N+1][N+1]; cout<<"连通带权图的矩阵为:"<

cin>>c[i][j]; } } cout<<"Prim算法最小生成树选边次序如下:"< //参数为结点个数n,和无向带权图中各结点之间的距离c[][N+1] void Prim(int n,Type c[][N+1]) { Type lowcost[N+1]; //记录c[j][closest]的最小权值 int closest[N+1]; //V-S中点j在s中的最临接顶点 bool s[N+1]; //标记各结点是否已经放入S集合| s[1]=true; //初始化s[i],lowcost[i],closest[i] for(int i=2;i<=n;i++) { lowcost[i]=c[1][i]; closest[i]=1; s[i]=false; } for(int i=1;i

算法设计实验_贪心算法背包问题

《算法分析与设计》 课程实验 专业年级:信息与计算科学 学生学号: 学生姓名: 实验题目:用贪婪法求解背包问题 指导老师: 实验时间:20xx年xx月x日 一、实验内容 用贪婪法求解背包问题 要求:用非递归实现 二、实验步骤 2.1、理解算法思想和问题要求; 2.2、写出每个操作的算法 非递归算法: greedbag() { int N; int c;

int[] w; int[] v; Scanner scan=new Scanner(System.in); System.out.print("输入背包的容量:"); c=scan.nextInt(); System.out.print("输入物品的数量:"); N=scan.nextInt(); System.out.print("分别输入物品的价值:"); v=new int[N]; for(int i=0;i

贪心算法概论

贪心算法概论 贪心算法一般来说是解决“最优问题”,具有编程简单、运行效率高、空间 复杂度低等特点。是信息学竞赛中的一个有为武器,受到广大同学们的青睐。本 讲就贪心算法的特点作些概念上的总结。 一、贪心算法与简单枚举和动态规划的运行方式比较 贪心算法一般是求“最优解”这类问题的。最优解问题可描述为:有n个输入,它的解是由这n 个输入的某个子集组成,并且这个子集必须满足事先给定的条 件。这个条件称为约束条件。而把满足约束条件的子集称为该问题的可行解。这 些可行解可能有多个。为了衡量可行解的优劣,事先给了一个关于可行解的函数,称为目标函数。目标函数最大(或最小)的可行解,称为最优解。 a)求“最优解”最原始的方法为搜索枚举方案法(一般为回溯法)。 除了极简单的问题,一般用深度优先搜索或宽度优先搜索。通常优化方法为利用约束条件进行可行性判断剪枝;或利用目标函数下界(或上界),根据当前最 优解进行分枝定界。 b)其次现今竞赛中用的比较普遍的动态规划(需要满足阶段无后效性原则)。 动态规划主要是利用最最优子问题的确定性,从后向前(即从小规模向大规模)得到当前最优策略,从而避免了重复的搜索。 举例说明:求多段图的最短路径。

在图(1)中,我们省略了各线段的长度。 如果用回溯法,搜索树大致如下: 显然,上面的搜索有大量重复性工作。比如节点8、9、10到11的最短路分别被调用了9次,从节点5、6、7到节点11也分别搜索了3次。 如果先算出节点8、9、10到11的最短路,由于它与前面的点无关,因此最优值确定下来,再用它们求定节点5、6、7 到节点11 的最短路径。同理,再用节 点5、6、7 的最优值,来求节点2、3、4 优值。最后从节点2、3、4 推出1 到 11的最优值。显然复杂度大为降低。 当然,如果本题把简单搜索改为搜索+记忆化的方法,则就是得能动态规划的原理,本质上就是动态规划,只是实现的方法不同与传统的表格操作法。搜索+记忆化算法有其特有的特点,以后再讨论。 c)贪心算法则不同,它不是建立在枚举方案的基础上的。它从前向后,根据当前情况,“贪心地”决定出下一步,从而一步一步直接走下去,最终得到解。 假如上面的例子中,我们定下这样的贪心策略:节点号k%3= =1。则有图3:

【精选】贪心算法的应用

贪心算法的应用 课程名称:算法设计与分析 院系:计算机科学与信息工程学院 学生姓名:**** 学号:********** 专业班级:********************************** 指导教师:****** 201312-27

贪心算法的应用 摘要:顾名思义,贪心算法总是作出在当前看来最好的选择。也就是说贪心算法并不从整体最优考虑,它所作出的选择只是在某种意义上的局部最优选择。当然,希望贪心算法得到的最终结果也是整体最优的。虽然贪心算法不能对所有问题都得到整体最优解,但对许多问题它能产生整体最优解。如单源最短路经问题,最小生成树问题等。在一些情况下,即使贪心算法不能得到整体最优解,其最终结果却是最优解的很好近似。贪心算法求问题一般具有两个重要性质:贪心选择性质和最优子结构性质。所谓贪心选择性是指所求问题的整体最优解可以通过一系列局部最优解的选择,即贪心选择达到。这是贪心算法可行的第一个基本要素,也是贪心算法与动态规划算法主要区别。当一个问题的最优解包含其子问题的最优解时,称此问题具有最优子结构性质。问题的最优子结构性质是该问题可用动态规划算法或贪心算法求解的关键特征。 背包问题是一个经典的问题,我们可以采用多种算法去求解0/1背包问题,比如动态规划法、分支限界法、贪心算法、回溯法。在这里我们采用贪心法解决这个问题。 关键词:贪心法背包问题最优化

目录 第1章绪论 (3) 1.1 贪心算法的背景知识 (3) 1.2 贪心算法的前景意义 (3) 第2章贪心算法的理论知识 (4) 2.1 问题的模式 (4) 2.2 贪心算法的一般性描述 (4) 第3章背包问题 (5) 3.1 问题描述 (5) 3.2 问题分析 (5) 3.3算法设计 (5) 3.4 测试结果与分析 (10) 第4章结论 (12) 参考文献 (13) 附件 (13)

贪心算法详解分析

贪心算法详解 贪心算法思想: 顾名思义,贪心算法总是作出在当前看来最好的选择。也就是说贪心算法并不从整体最优考虑,它所作出的选择只是在某种意义上的局部最优选择。当然,希望贪心算法得到的最终结果也是整体最优的。虽然贪心算法不能对所有问题都得到整体最优解,但对许多问题它能产生整体最优解。如单源最短路经问题,最小生成树问题等。在一些情况下,即使贪心算法不能得到整体最优解,其最终结果却是最优解的很好近似。 贪心算法的基本要素: 1.贪心选择性质。所谓贪心选择性质是指所求问题的整体最优解可以通过一系列局部最优的选择,即贪心选择来达到。这是贪心算法可行的第一个基本要素,也是贪心算法与动态规划算法的主要区别。 动态规划算法通常以自底向上的方式解各子问题,而贪心算法则通常以自顶向下的方式进行,以迭代的方式作出相继的贪心选择,每作一次贪心选择就将所求问题简化为规模更小的子问题。 对于一个具体问题,要确定它是否具有贪心选择性质,必须证明每一步所作的贪心选择最终导致问题的整体最优解。 2. 当一个问题的最优解包含其子问题的最优解时,称此问题具有最优子结构性质。问题的 最优子结构性质是该问题可用动态规划算法或贪心算法求解的关键特征。 贪心算法的基本思路: 从问题的某一个初始解出发逐步逼近给定的目标,以尽可能快的地求得更好的解。当达到算法中的某一步不能再继续前进时,算法停止。 该算法存在问题: 1. 不能保证求得的最后解是最佳的; 2. 不能用来求最大或最小解问题; 3. 只能求满足某些约束条件的可行解的范围。 实现该算法的过程: 从问题的某一初始解出发; while 能朝给定总目标前进一步do 求出可行解的一个解元素; 由所有解元素组合成问题的一个可行解; 用背包问题来介绍贪心算法: 背包问题:有一个背包,背包容量是M=150。有7个物品,物品可以分割成任意大小。要 求尽可能让装入背包中的物品总价值最大,但不能超过总容量。

C语言版贪心算法背包问题

#include<> #define N 100 typedef struct bao{ int num; float w; float v; }; typedef struct avg{ int num; ( float val; float w; float v; }; struct bao b[N]; struct avg d[N]; int n; float c; ^ void Sort() { int i,j,k; struct avg temp[N]; for(i=0;i

float x[N],sum = 0; for(i=0;ic) break; x[d[i].num] = 1; sum += d[i].v; c -= d[i].w; } if(i

背包问题(贪心算法)

算法分析与设计实验报告 第 4 次实验

}

附录:完整代码 #include #include #include struct node{ float value; float weight; }; float Value,curvalue=0; float Weight,curweight=0; //按价重比冒泡排序 void sort(node Node[],int M){ int i,j; node temp; for(i=0;i

贪心算法与动态规划的比较

贪心算法与动态规划的比较 【摘要】介绍了计算机算法设计的两种常用算法思想:贪心算法与动态规划算法。通过介绍两种算法思想的基本原理,比较两种算法的联系和区别。通过背包问题对比了两种算法的使用特点和使用范围。 【关键字】动态规划;贪心算法;背包问题 1、引言 为了满足人们对大数据量信息处理的渴望,为解决各种实际问题,计算机算法学得到了飞速的发展,线性规划、动态规划、贪心策略等一系列运筹学模型纷纷运用到计算机算法学中,产生了解决各种现实问题的有效算法。虽然设计一个好的求解算法更像是一门艺术而不像是技术,但仍然存在一些行之有效的、能够用于解决许多问题的算法设计方法,你可以使用这些方法来设计算法,并观察这些算法是如何工作的。一般情况下,为了获得较好的性能,必须对算法进行细致的调整。但是在某些情况下,算法经过调整之后性能仍无法达到要求,这时就必须寻求另外的方法来求解该问题。本文针对部分背包问题和0/ 1 背包问题进行分析,介绍贪心算法和动态规划算法的区别。 2、背包问题的提出 给定n种物品( 每种物品仅有一件) 和一个背包。物品i的重量是w i,其价值为p i,背包的容量为M。问应如何选择物品装入背包,使得装入背包中的物品的总价值最大,每件物品i的装入情况为x i,得到的效益是p i*x i。 ⑴部分背包问题。在选择物品时,可以将物品分割为部分装入背包,即0≤x i≤1 ( 贪心算法)。 ⑵0/ 1背包问题。和部分背包问题相似,但是在选择物品装入时要么不装,要么全装入,即x i = 1或0。( 动态规划算法) 。 3、贪心算法 3.1 贪心算法的基本要素 能够使用贪心算法的许多例子都是最优化问题,每个最优化问题都包含一组限制条件和一个优化函数,符合限制条件的问题求解方案称为可行解;使优化函数取得最佳值的可行解称为最优解。此类所求问题的整体最优解可以通过一系列局部最优的选择,即贪心选择来达到(这是贪心算法与动态规划的主要区别) 。 3.2贪心策略的定义 贪心策略是指从问题的初始状态出发,通过若干次的贪心选择而得出最优值( 或较优解) 的一种解题方法。贪心策略总是做出在当前看来是最优的选择,也就是说贪心策略并不是从整体上加以考虑,它所做出的选择只是在某种意义上的局部最优解,而许多问题自身的特性决定了该问题运用贪心策略可以得到最优解或较优解。(注:贪心算法不是对所有问题都能

贪心算法背包问题

算法设计与分析实验报告 题目:贪心算法背包问题 专业:JA V A技术xx——xxx班 学号: 姓名: 指导老师:

实验三:贪心算法背包问题 一、实验目的与要求 1、掌握背包问题的算法 2、初步掌握贪心算法 二、实验题: 问题描述:与0-1背包问题相似,给定n种物品和一个背包。物品i的重量是wi,其价值为vi,背包的容量为c。与0-1背包问题不同的是,在选择物品i装入背包时,背包问题的解决可以选择物品i的一部分,而不一定要全部装入背包,1< i < n。 三、实验代码 import java.awt.*; import java.awt.event.*; import javax.swing.*; public class er extends JFrame { private static final long serialVersionUID = -1508220487443708466L; private static final int width = 360;// 面板的宽度 private static final int height = 300;// 面板的高度 public int M; public int[] w; public int[] p; public int length; er() { // 初始Frame参数设置 this.setTitle("贪心算法"); setDefaultCloseOperation(EXIT_ON_CLOSE); setSize(width, height); Container c = getContentPane(); c.setLayout(new BoxLayout(c, BoxLayout.Y_AXIS)); setLocation(350, 150); // 声明一些字体样式 Font topF1 = new Font("宋体", Font.BOLD, 28); Font black15 = new Font("宋体", Font.PLAIN, 20); Font bold10 = new Font("宋体", Font.BOLD, 15); // 声明工具栏及属性设置 JPanel barPanel = new JPanel(); JMenuBar topBar = new JMenuBar(); topBar.setLocation(1, 1); barPanel.add(topBar); // 面板1和顶部标签属性设置 JPanel p1 = new JPanel(); JLabel topLabel = new JLabel("背包问题");

贪婪算法在排课问题中分析与应用

贪婪算法在排课问题中分析与应用 摘要:排课问题是教学管理中重要的问题,对教学质量起到十分重要的影响。随着计算机和信息技术的快速发展,通过合理的算法编制排课系统是十分合适的。本文通过排课问题算法的分析,选择贪婪算法来解决排课问题。通过实验表明,目前的算法能够很好的解决排课问题,对问题的解决的复杂度大大降低,使得排课变得十分简单和高效。 关键字:排课,贪婪算法,优先级 1、绪论 在高校日常管理中,教学计划是重要的组成部分。而教学计划的重要体现方式之一就是排课表,其在教学管理中的地位和作用不可低估,课表的管理对教学管理是起到基础和重要的作用。因此排课问题是教学管理中重要的问题,对教学质量起到十分重要的影响。 由于上课约束条件多,课表的编制十分复杂,是一个耗时耗力的工作。目前随着高校人数的越来越多,其很难用手工去编制课表,其工作时间长,工作量大和繁琐的编制过程是一般人很难驾驭的。随着计算机和信息技术的快速发展,通过合理的算法编制排课系统是十分合适的。通过计算机算法的求解来对问题进行抽象和解决。 2、排课算法算法简介 目前对于排课问题的算法较多,主要有蚁群算法、模拟退火算法、遗传算法、整数规划法和贪婪算法等。 (1)蚁群算法 蚁群算法就是将模拟蚂蚁的活动,对参数设置较少。这种算法具备较强的全局搜索能力,但其效率较低,且容易出现停滞[1]。 (2)模拟退火算法 这个算法被较多的学者用来解决排课问题,它是模拟退火的现象,对自然事物进行抽象而来。其比较适合约束条件较少的问题。如果约束条件少,其很快就能获得最优解。但这种算法的参数选择较难,且资源开销大[2]。 (3)遗传算法 遗传算法是基于自然选择和生物遗传的全局优化策略。其优点在于在非线性问题上能够表现出全局最优,可以并行处理而且算法效率相对较高[3]。 但遗传算法本身较为复杂,由于排课问题的约束条件较多,其算法的效率较低,如果排课要求十分严格的话,很有可能造成找不到解。 (4)整数规划法 整数规划法来解决排课问题计算量很大,只适合规模较小排课问题,对于规模较大的,至今都很难找到一个可行算法。 (5)贪婪算法 贪婪算法是指在解决问题的时候,不会考虑整体最优,而是采取局部最优的思想进行最优思想[4]。也就是说,该算法将解决问题分解为每一个步骤,根据其难易程度进行解决,通过满足局部最优的方式来尽可能的获得最满意的解决。虽然在某些情况下,贪婪算法并不能得到最优解,但能得到相对满意的解。 3、排课问题综述 (1)排课原则 排课问题的本质是一个优化问题,是对教师、上课课程、上课时间和上课地点等因素的优化。其目的就是将全校所开设课程在有限的时间和地点下进行合理的安排,确保教学的顺利进行,以达到最优的效果。 为了能够产出一张满意合格的排课表,在排课中要满足一些约束条件。我们将一些约束

0-1背包问题的算法设计策略对比与讲解

算法设计与分析大作业 班级:电子154 姓名:吴志勇 学号: 1049731503279 任课老师:李瑞芳 日期: 2015.12.25

算法设计与分析课程论文 0-1背包问题的算法设计策略对比与分析 0 引言 对于计算机科学来说,算法的概念是至关重要的。在一个大型软件系统的开发中,设计出有效的算法将起到决定性的作用。通俗的讲,算法是解决问题的一种方法。也因此,《算法分析与设计》成为计算科学的核心问题之一,也是计算机科学与技术专业本科及研究生的一门重要的专业基础课。算法分析与设计是计算机软件开发人员必修课,软件的效率和稳定性取决于软件中所采用的算法;对于一般程序员和计算机专业学生,学习算法设计与分析课程,可以开阔编程思路,编写出优质程序。通过老师的解析,培养我们怎样分析算法的“好”于“坏”,怎样设计算法,并以广泛用于计算机科学中的算法为例,对种类不同难度的算法设计进行系统的介绍与比较。本课程将培养学生严格的设计与分析算法的思维方式,改变随意拼凑算法的习惯。本课程要求具备离散数学、程序设计语言、数据结构等先行课课程的知识。 1 算法复杂性分析的方法介绍 算法复杂性的高低体现在运行该算法所需要的计算机资源的多少上,所需的资源越多,该算法的复杂性越高;反之,所需资源越少,该算法的复杂性越低。对计算机资源,最重要的是时间与空间(即存储器)资源。因此,算法的复杂性有时间复杂性T(n)与空间复杂性S(n)之分。 算法复杂性是算法运行所需要的计算机资源的量,这个量应集中反映算法的效率,并从运行该算法的实际计算机中抽象出来,换句话说,这个量应该只依赖要解决的问题规模‘算法的输入和算法本身的函数。用C表示复杂性,N,I和A表示问题的规模、算法的输入和算法本身规模,则有如下表达式: C=F(N,I,A) T=F(N,I,A) S=F(N,I,A) 其中F(N,I,A)是一个三元函数。通常A隐含在复杂性函数名当中,因此表达式中一般不写A。 即:C=F(N,I) T=F(N,I) S=F(N,I) 算法复杂性中时间与空间复杂性算法相似,所以以下算法复杂性主要以时间复杂性为例: 算法的时间复杂性一般分为三种情况:最坏情况、最好情况和平均情况。下面描述算法复杂性时都是用的简化的复杂性算法分析,引入了渐近意义的记号O,Ω,θ,和o。 O表示渐近上界Ω表示渐近下界: θ表示同阶即:f(n)= O(g(n))且 f(n)= Ω(g(n)) 2 常见的算法分析设计策略介绍 2.1 递归与分治策略 分治法的设计思想是,将一个难以直接解决的大问题,分割成一些规模较小的相同问题,以便各个击破,分而治之。 直接或间接地调用自身的算法称为递归算法。用函数自身给出定义的函数称为递归函数。 由分治法产生的子问题往往是原问题的较小模式,这就为使用递归技术提供了方便。在这种情况下,反复应用分治手段,可以使子问题与原问题类型一致而其规模却不断缩小,最终使子问题缩小到很容易直接求出其解。这自然导致递归过程的产生。 分治与递归像一对孪生兄弟,经常同时应用在算法设计之中,并由此产生许多高效算法。 递归算法举例: 共11页第1页

贪 心 算 法

【贪心算法】思想 & 基本要素 & 贪心算法与局部最优 & 贪心算法与动态规划的区别 & 运用贪心算法求解问题 首先我们先代入问题来认识一下贪心算法涉及的问题 找钱问题 给顾客找钱,希望找零的钞票尽可能少,零钱种类和数量限定 找钱问题满足最优子结构 最快找零(贪心):为得到最小的找零次数,每次最大程度低减少零额活动安排问题 设个活动都需要使用某个教室,已知它们的起始时间和结束时间,求合理的安排使得举行的活动数量最多 贪心:使得每次安排后,教室的空闲时间最多 解决过程如下: 贪心算法求得的相容活动集是最大的 第一步:证明最优解中包含结束时间最早的活动 设相容集 A 是一个最优解,其结束最早的活动为 a,则 ( A - { a }) U { 1 } 也是一个最优解 第二步:证明去掉结束时间最早的活动后,得到的子问题仍是最优的:反证法 理解贪心算法 贪心算法总是做出当前最好的选择 贪心选择的依据是当前的状态,而不是问题的目标

贪心选择是不计后果的 贪心算法通常以自顶向下的方法简化子问题 贪心算法求解的问题具备以下性质 贪心选择性质:问题的最优解可以通过贪心选择实现 最优子结构性质:问题的最优解包含子问题的最优解 贪心选择性质的证明 证明问题的最优解可以由贪心选择开始 即第一步可贪心 证明贪心选择后得到的子问题满足最优子结构 即步步可贪心 背包问题 问题描述:给定 n 个物品和一个背包。物品 i 的重量为 Wi ,价值为 Vi ,背包的容量为 c ,问如何选择物品或物品的一部分,使得背包中物品的价值最大? 当 n = 3 ,c = 50 0-1背包问题:装入物品2、3,最大价值220 背包问题:装入物品1、2和2-3的物品3,最大价值240(贪心算法)贪心算法无法求解0-1背包问题,按贪心算法,0-1背包问题将装入物品1和2 贪心与局部最优 思考:为什么0-1背包可以用动态规划?而不能用贪心算法 贪心易陷入局部最优

算法分析与设计选修课-贪心算法应用研究

武汉理工大学 算法设计与分析论文题目:贪心算法应用研究 姓名:吴兵 学院:信息工程 专业班级:电子133 学号: 1409721303131 任课教师:张小梅

目录 摘要 (1) 1.绪论 (2) 2贪心算法的基本知识概述 (3) 2.1 贪心算法定义 (3) 2.2 贪心算法的基本思路及实现过程 (3) 2.3贪心算法的核心 (3) 2.4贪心算法的基本要素 (4) 2.5 贪心算法的理论基础 (6) 2.6 贪心算法存在的问题 (7) 3贪心算法经典应用举例 (8) 3.1删数问题 (8) 3.2 汽车加油问题 (10) 3.3会场安排问题 (12) 4.总结 (16) 5.参考文献 (17)

摘要 在求最优解问题的过程中,依据某种贪心标准,从问题的初始状态出发,直接去求每一步的最优解,通过若干次的贪心选择,最终得出整个问题的最优解,这种求解方法就是贪心算法。从贪心算法的定义可以看出,贪心法并不是从整体上考虑问题,它所做出的选择只是在某种意义上的局部最优解,而由问题自身的特性决定了该题运用贪心算法可以得到最优解。贪心算法所作的选择可以依赖于以往所作过的选择,但决不依赖于将来的选择,也不依赖于子问题的解,因此贪心算法与其它算法相比具有一定的速度优势。如果一个问题可以同时用几种方法解决,贪心算法应该是最好的选择之一。本文讲述了贪心算法的含义、基本思路及实现过程,贪心算法的核心、基本性质、特点及其存在的问题。并通过贪心算法的特点举例列出了以往研究过的几个经典问题,对于实际应用中的问题,也希望通过贪心算法的特点来解决。 关键词:贪心算法最小生成树多处最优服务次序问题删数问题

c应用贪心算法求解背包问题

实验五应用贪心算法求解背包问题 学院:计算机科学与技术专业:计算机科学与技术 学号:班级:姓名: 、 实验内容: 背包问题指的是:有一个承重为W的背包和n个物品,它们各自的重量和价值分别是n ,假设W w i和v i(1 i n)w i 1i,求这些物品中最有价值的一个子集。如果每次选择某一个物品的时候,只能全部拿走,则这一问题称为离散(0-1)背包问题;如果每次可以拿走某一物品的任意一部分,则这一问题称为连续背包问题。 二、算法思想: 首先计算每种物品单位重量的价值Vi/Wi,然后,依贪心选择策略,将尽可能多的单位重量价值最高的物品装入背包。若将这种物品全部装入背包后,背包内的物品总重量未超过C,则选择单位重量价值次高的物品并尽可能多地装入背包。依此策略一直地进行下去,直到背包装满为止。 三、实验过程: #in elude using n amespace std; struct goodi nfo

{ float p; // 物品效益 float w; // 物品重量 float X; // 物品该放的数量 int flag; // 物品编号 };// 物品信息结构体 void Insertionsort(goodinfo goods[],int n)// 插入排序,按pi/wi 价值收益进行排序,一般教材上按冒泡排序 { int j,i; for(j=2;j<=n;j++) { goods[0]=goods[j]; i=j-1; while (goods[0].p>goods[i].p) { } goods[i+1]=goods[0]; } }// 按物品效益,重量比值做升序排列goods[i+1]=goods[i]; i--; void bag(goodinfo goods[],float M,int n) { float cu; int i,j;

贪心算法实现背包问题算法设计与分析实验报告

算法设计与分析实验报告 实验名称贪心算法实现背包问题评分 实验日期年月日指导教师 姓名专业班级学号 一.实验要求 1. 优化问题 有n个输入,而它的解就由这n个输入满足某些事先给定的约束条件的某个子集组成,而把满足约束条件的子集称为该问题的可行解。可行解一般来说是不唯一的。那些使目标函数取极值(极大或极小)的可行解,称为最优解。 2.贪心法求优化问题 算法思想:在贪心算法中采用逐步构造最优解的方法。在每个阶段,都作出一个看上去最优的决策(在一定的标准下)。决策一旦作出,就不可再更改。作出贪心决策的依据称为贪心准则(greedy criterion)。 3.一般方法 1)根据题意,选取一种量度标准。 2)按这种量度标准对这n个输入排序 3)依次选择输入量加入部分解中。如果当前这个输入量的加入,不满足约束条件,则不把此输入加到这部分解中。 procedure GREEDY(A,n) /*贪心法一般控制流程*/ //A(1:n)包含n个输入// solutions←φ //将解向量solution初始化为空/ for i←1 to n do x←SELECT(A) if FEASIBLE(solution,x) then solutions←UNION(solution,x) endif repeat return(solution) end GREEDY 4. 实现典型的贪心算法的编程与上机实验,验证算法的时间复杂性函数。 二.实验内容 1. 编程实现背包问题贪心算法。通过具体算法理解如何通过局部最优实现全局最优,

并验证算法的时间复杂性。 2.输入5个的图的邻接矩阵,程序加入统计prim算法访问图的节点数和边数的语句。 3.将统计数与复杂性函数所计算比较次数比较,用表格列出比较结果,给出文字分析。 三.程序算法 1.背包问题的贪心算法 procedure KNAPSACK(P,W,M,X,n) //P(1:n)和W(1;n)分别含有按 P(i)/W(i)≥P(i+1)/W(i+1)排序的n件物品的效益值 和重量。M是背包的容量大小,而x(1:n)是解向量 real P(1:n),W(1:n),X(1:n),M,cu; integer i,n; X←0 //将解向量初始化为零 cu←M //cu是背包剩余容量 for i←1 to n do if W(i)>cu then exit endif X(i) ←1 cu←cu-W(i) repeat if i≤n then X(i) ←cu/ W(i) endif end GREEDY-KNAPSACK procedure prim(G,) status←“unseen” // T为空 status[1]←“tree node” // 将1放入T for each edge(1,w) do status[w]←“fringe” // 找到T的邻接点 dad[w] ←1; //w通过1与T建立联系 dist[w] ←weight(1,w) //w到T的距离 repeat while status[t]≠“tree node” do pick a fringe u with min dist[w] // 选取到T最近的节点 status[u]←“tree node” for each edge(u,w) do 修改w和T的关系 repeat repeat 2.Prim算法

贪心算法实现01背包问题

贪心算法实现01背包问题 算法思想:贪心原则为单位价值最大且重量最小,不超过背包最大承重量为约束条件。也就是说,存在单位重量价值相等的两个包,则选取重量较小的那个背包。 具体实现过程是:首先可以设置一个备份pvu类型的数组,在不破环原数据的情况下,对此备份数组按单位重量价值从大到小的排序。依次设立两个指针i,j(其中i表示当前应该参与最佳pv值的元素指针,j表示符合约束条件的指针(单位重量价值PV最大,重量最小,不超过最大承重量约束) 代码实现如下: #include using namespace std; typedef struct { int v; int w; float pv; }pvu; void sortByPv(pvu [],int ); int zeroneBags(pvu[],int,int,int * ); void print(pvu a[],int n) { for (int i=0;i

贪心算法的应用实例

贪心算法的应用实例 例2.排队问题 【题目描述】 在一个医院B 超室,有n个人要做不同身体部位的B超,已知每个人需要处理的时间为ti,(00,从而新的序列比原最优序列好,这与假设矛盾,故s1为最小时间,同理可证s2…sn依次最小。 例3.:数列极差问题 【题目描述】 在黑板上写了N个正整数做成的一个数列,进行如下操作:每一次擦去其中的两个数a 和b,然后在数列中加入一个数a×b+1,如此下去直至黑板上剩下一个数,在所有按这种操作方式最后得到的数中,最大的max,最小的为min,则该数列的极差定义为M=max-min。 编程任务:对于给定的数列,编程计算出极差M。 输入输出样例: 输入: 4 2 1 4 3 输出: 13 【算法分析】 当看到此题时,我们会发现求max与求min是两个相似的过程。若我们把求解max与min的过程分开,着重探讨求max的问题。 下面我们以求max为例来讨论此题用贪心策略求解的合理性。 讨论:假设经(N-3)次变换后得到3个数:a ,b , max'(max'≥a≥b),其中max'是(N-2)个数经(N-3)次f变换后所得的最大值,此时有两种求值方式,设其所求值分别为 z1,z2,则有:z1=(a×b+1)×max'+1,z2=(a×max'+1)×b+1所以z1-z2=max'-b≥0若经(N-2)次变换后所得的3个数为:m,a,

2贪心算法解决部分背包问题

2贪心算法解决部分背包问题 一、实验目的 学习掌贪心算法法思想。 二、实验内容 用贪心法解决部分背包问题。给定n种物品和一个背包。物品i的重量是Wi,其价值为pi,背包的容量为M,将物品i的一部分xi放入背包会得到pi xi的效益。应如何选择装入背包的物品,使得装入背包中物品的总价值最大?给出具体的装包方案。在选择装入背包的物品时,对每种物品i,可以整件装入背包、不装入背包或部分装入背包。但不能将物品i装入背包多次。 四、需求分析 对于给定n种物品和一背包。在容量最大值固定的情况下,要求装入的物品价值最大化。 五、基本思想: 贪婪法是解决最优化问题时的一种简单但适用范围有限的策略。总是对当前的问题作最好的选择,也就是局部寻优。最后得到整体最优。总是选择单位价值最高的物品。 六、详细设计 #include using namespace std; struct _Object//物品结构体 { int Value;//物品价值 int Weight;//物品重量 int AveValue;//物品单位价值 float Num;//物品可以放入的数量

void knaspsack(int n,float M,_Object object[]) { //n为物品个数,M为背包容量 int i; float C=M; for(i=0;iC)break;//当物品重量大于背包容量时 else//小于时 { object[i].Num=1;//物品i放入一件 C-=object[i].Weight;//背包容量减小 } } if(i<=n)//当不能放入整个物品时,选取物品一部分放入 object[i].Num=C/object[i].Weight; for(i=0;i0) cout<<"重量为: "<

相关文档
最新文档