acm课程总结报告
Posted mRango
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了acm课程总结报告相关的知识,希望对你有一定的参考价值。
本学期的选修课ACM程序设计进入尾声,首先要总结的当然是感谢老师这类的客套话,良心话是真的谢谢费老耐心认真的教学,确实学到了很多东西,这一点从数据结构这门课的学习中容易看出,轻松很多。
本学期总共学习里四个专题:第一讲贪心算法,第二讲搜索,第三讲动态规划以及现在正在 努力做的图。下面我将以这四个专题为基础分别讲解ACM中所获得知识内容,感悟。
专题一贪心算法。
贪心算法包括计算活动安排的贪心算法,背包问题,删数问题。他的理论基础有三点,1,在问题的每一步选择中都采取在当前状态下最好或者最优的选择,希望得到的结果是最好或者最优。2,能够得到某种度量意义下的最优解的分级处理。通过一系列的选择得到问题的解,而他所做的每一步都是每一级当前状态下的最好选择。即希望通过问题的局部最优解求出整个问题的最优解。3,他很简洁,对很对问题都能产生最优解,但是不能保证总是有效,因为他并不是针对所有问题。
贪心算法这种策略需要解决两个问题:(1)该题是否适合于贪心的策略。(2)如何选择贪心标准,才能得到问题的最优解。
贪心算法的求解过程有不是一年硬性要求的五步。1,候选集合,构造集合,问题公众的所有解均来自于她。2,解集合S,S不断拓展,直到构成满足问题的完整解。3,解决函数SOLUTION检查S是否构成问题完整解。4,选择函数SELECT,这就是贪心策略了,这是关键。5,可行函数FEASIABLE 检查解集合中加入一个候选对象是否可行,即扩展的约束条件。
一, 计算活动安排的贪心算法。设有n个活动的集合E={1,2,3,4,n}每个活动都要求使用同一演讲会场,同一时间内只有一个活动能使用这一资源,每个活动都有起始时间结束时间。这一问题就是能选出怎么安排活动才使更多的活动能被举办。这个题的贪心 首先应该按活动结束时间的早晚排序,结束早的在前面。第一个活动必须选,然后在不与第一个活动冲突的活动中选取结束最早的,这样每次选择,就选择符合要求的情况下,结束时间早的,达到了一个贪心的目的,这样选择完后,得到的解集合,就是最优解。
二, 背包问题。给定一个载重量为M的背包,考虑n个物品,其中第i个物品的重量,价值为Wi,要求把物品装满背包,且是背包内的物品价值获得最大。这里分为两种,一种还可以分割的最好用贪心算法,一种是不能分割的动态规划,这里讨论第一种能分割的。步骤一般是,先按物品的性价比从大到小排序,然后往背包中放,最后剩余的空间就把物品分割开来。这样性价比最优就是贪心的准则,每次都是最优,就达到了整体的最优。
三, 删数问题。给定n位正整数a,去掉k位后的数字,按原来次序排列,组成一个新的整数,设计算法,求得删除数后组成新数后,最小。N位数a可以表示为x1x2x3…xn要删除k位数,使得剩下的数字组成的整数最小。贪心算法采用最近下降点的贪心策略,即x1<x2<x3<x4..<xi-1<xi如果xi+1<xi(下降点)则删去xi,即得到得到一个新数且这个心为n-1位中最小的N直到删除k个为止。
总结:贪心算法不是从整体上考虑问题,她做出的选择只是某种意义上的局部最优,局部最优,得到整体最优,这就是贪心算法的大思想。利用贪心法则,最重要的是找到贪心标准。根据贪新标准去求解问题。
专题二搜索。
主要讲解的是二分查找,(三分查找),深度搜素,广度搜索。二分查找相对基础,在一个单调有序的集合中查找元素,每次不断的折半。就是不断地折半直到找到目标为止。三分查找,当需求的某凸性或者凹性函数的极致是,就使用三分查找来不断地逼近求解。广度优先搜索(BFS),利用规则,生成所有可能的状态,把所有的状态根据规则生成树,广度优先的思想是,一层一层的查找遍历。深度优先搜索是根据题意生成树,依照规则从一个节点一直查找下去,还是没有查找到时,利用回溯,到初始层面重复上一过程。
一, 二分查找,在一个单调有序的集合中查找元素,每次将集合分为左右两部分,判断解在哪个部分中并调整集合上下界,重复直到找到目标元素。主要模板是 mid = (high + low)/2 if(calculate(mid) < x) low = mid; elsehigh = mid;其判断条件是high – low > 1.0e-6就是high与low无限接近.有时候可以用递归来做。
二, 三分查找主要解决的是问题中与数学中二次函数相吻合的问题。凸函数或者凹函数。他的模板是 left 与 right mid = (left + right)/2 midmid = (mid+ right)/2;如果mid靠近极值点,则right = midmid;否则,则left = mid;
三, 广度搜索(BFS)基本思想:从初始状态S 开始,利用规则,生成所有可能的状态。构成的下一层节点,检查是否出现目标状态G,若未出现,就对该层所有状态节点,分别顺序利用规则。生成再下一层的所有状态节点,对这一层的所有状态节点检查是否出现G,若未出现,继续按上面思想生成再下一层的所有状态节点,这样一层一层往下展开。直到出现目标状态为止。一层层的遍历,这样正好符合队列先进先出的性质,所以广度搜索一般用对来做。具体的过程是1,每次取出队列首元素(初始状态),进行拓展。2,把拓展所得到的可行状态都放进队列之中。3,将初始状态删除。4,一直进行以上三步直到队列为空。广度优先搜索的框架: while not queue.empty() begin tmp = queue.top() 从tmp循环拓展下一个状态next if状态next合法then begin 生成新状态next next.step = tmp.step+1 queue.pushback(next) end;queue.pop();
四, 深度搜索(DFS)基本思想是:从初始状态,利用规则生成搜索树下一层任一个结点,检查是否出现目标状态,若未出现,以此状态利用规则生成再下一层任一个结点,再检查,重复过程一直到叶节点(即不能再生成新状态节点),当它仍不是目标状态时,回溯到上一层结果,取另一可能扩展搜索的分支。采用相同办法一直进行下去,直到找到目标状态为止。状态必须在遍历完所有他的子状态后,才能继续进行对同一层中下一个状态的遍历,这符合栈的先进后出的性质,也可以用递归来做,一般应栈来进行操作。具体过程:1,每次取出栈顶的元素,对其进行拓展。2,若栈顶元素无法进行继续拓展,则将其从栈中弹出,继续进行1过程。3,不断重复直到获得目标状态为止,或者栈为空(无解)。深度优先搜索的框架:递归实现:Function Dfs (Int Step, 当前状态) Begin 可加结束条件 从当前状态循环拓展下一个状态Next If 状态Next合法 Then Dfs(Step + 1, Next )) End;
总结:搜索算法比为枚举算法有了一定的方向性和目标性。算法是在解的空间里,从一个状态转移(按照要求拓展)到其他状态,这样进行下去,将解的空间中的状态遍历,找到答案(目标的状态)。
专题三动态规划。动态规划是解决多阶段决策问题的一种方法。和贪心相似。多阶段决策问题:如果一类问题的求解过程可以分为若干个互相联系的阶段,在每一个阶段都需作出决策,并影响到下一个阶段的决策,从而确定了一个过程的活动路线,则称它为多阶段决策问题。多阶段决策问题,就是要在可以选择的那些策略中间,选取一个最优策略,使在预定的标准下达到最好的效果. 他一般包括,最大上升子序列问题。最大字串问题。背包问题。
动态规划的最优性原理:
1, 不论初始状态和第一步决策是什么,余下的决策相对于前一次决策所产生的新状态,构成一个最优决策序列;
2, 最优决策序列的子序列,一定是局部最优决策子序列;
3, 3,包含有非局部最优的决策子序列,一定不是最优决策序列。
动态规划的指导思想:
1, 在做每一步决策时,列出各种可能的局部解
2, 依据某种判定条件,舍弃那些肯定不能得到最优解的局部解。
3, 以每一步都是最优的来保证全局是最优的。
动态规划一般的解法是递归。例题:小明写了一个简单的吃金币游戏,规则如下: 在一个长方形地图上,玩家每次能从一个方格走到相邻一个方格。 玩家控制的角色可以向下或者向右走,但不能向上或向左走。每个方格上都有一定的金币。现在,小明想请你帮他想一个策略,尽可能多的获得金币(从左上角走到右下角可能获得的最大金币数)。如果用F[a][b]表示达到(a,b)这个点时所能吃到的最大金币数量。
得到递推关系式:F[a][b]=max(F[a-1][b],F[a][b-1])+Coin[a][b](此步即为递归定义最优解的值,列出状态转移方程)F[m][n]即为所求。算法如下:int f[MAX][MAX],c;
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
{
cin>>c;
f[i][j]=max(f[i][j-1],f[i-1][j])+c;
}
cout<<f[m][n];
return 0;
动态规划的基本模型:
一, 动态规划问题具有以下基本特征:
二, 问题具有多阶段决策的特征。
三, 每一阶段都有相应的“状态”与之对应,描述状态的量称为“状态变量”。
四, 每一阶段都面临一个决策,选择不同的决策将会导致下一阶段不同的状态。
五, 每一阶段的最优解问题可以递归地归结为下一阶段各个可能状态的最优解问题,各子问题与原问题具有完全相同的结构。
动态规划问题的一班解题步骤:
一, 判断问题是否具有最优子结构性质,若不具备则不能用动态规划。
二, 把问题分成若干个子问题(分阶段)。
三, 建立状态转移方程(递推公式)。
四, 找出边界条件。
五, 将已知边界值带入方程。
六, 递推求解。
动态规划的一般性问题:
1, 最长子序列问题。比如,对于序列(1, 7, 3, 5, 9, 4, 8),有它的一些上升子序列,如(1, 7), (3, 4, 8)等等。这些子序列中最长的长度是4,比如子序列(1, 3, 5, 8). 输入两个字符串s1,s2,cin就可以解决,之后进行动态规划。如图建立dp[][]二维数组来记录。当比较到字符相同时,dp[i][j]这个位置的数是取dp[i-1][j] dp[i][j] dp[i][j-1]当中的最大值。而dp[i][j]的数由dp[i-1][j-1]得到。注意对角线对角线就是字符串。1 首先解释dp[i][j] = dp[i-1][j-1] + 1 如图a = a,b=b时ab = ab最长就是2 对角线正好对应着两个字符串相同位置上的字符2 dp[i-1][j]是当s1为abfc时,s2为abc时来相互比较,此时子序列为3 dp[i][j-1]是当s1为abf时,s2为abcf时来相互比较,此时子序列为3。
2, 0-1背包问题。典型题目:给你物品数目以及背包的容量,下面是各个物品的价值以及容量,让你求背包能装入的最大价值状态转移方程:dp[i][j] =most(dp[i][j],dp[i-1][j-w[i])+v[i]);w[i]即第i件物品的重量 v[i]第i件物品的价值dp[i][j]把前i件物品装入j容量的背包中所能获得的最大价值。对每件物品就有两种选择,放或者不放,取其最大值,如果放这件物品则为dp[i-1][j-w[i]] + v[i],前i-1件物品放入j-w[i]的容量中所能获得的最大价值,如果不放就是dp[i-1][j]。
3, 完全背包问题,在0/1背包问题的基础上,每种物品不单单是一件了,而是多件。子问题定义:F[i][j]表示前i种物品中选取若干件物品放入剩余空间为j的背包中所能得到的最大价值。 根据第i种物品放多少件进行决策dp[i][j] =max(f[i-1][j-k*w[i]) + k*v[i],f[i-1][j]) 0<=k*w[i]<=j 就是比0/1背包问题多加了一层每种物品数量的循环
4, 还有分组背包问题,把物品分成若干组,在每一组中求最优。
总结:动态规划就是 要找到问题划分阶段的条件,找到这个条件,列出状态转移方程,逐步求解,就能得到最终理想的答案。
专题四树。首先被告知的是什么是树,树就是一种逻辑结构, 有且仅有一个根节点。其余的是集合,包括节点与叶子节点。还有图,图的存储结构是邻接矩阵。列出以上图与树的概念就好为以下解决实际问题做好了完美的铺垫。专题四主要就是解决最短路径的问题。无论是村寨之间的最短路,还是城市的如何规划,都围绕最短路径。下面就解释最短路径的问题。
一. 并查集。即“不相交集合”。将编号分别为1…N的N个对象划分 为不相交集合,在每个集合中,选择其中某个元素代表所在集合。常见两种操作: 合并两个集合查找某元素属于哪个集合 模板算法:void made(int n) //并查集的初始化{ int i; for(i=1;i<=n;i++) father[i] = I;}int find(int x)//查找父结点找到集合中的代表元素{ if(x != father[x]) { father[x] = find(father[x]);} return father[x];}void unions(int x,int y) //两个元素合并成一个集合其实是组合{ x = y; y = find(y);if(x != y){father[x] = y;}}
二. 求最小生成树的prim算法:
1, 任取一个顶点加入生成树;
2, 在那些一个端点在生成树里,另一个端点不在生成树里的边中,取权最小的边,将它和另一个端点加进生成树。
3, 重复上一步骤,直到所有的顶点都进入了生成树为止。
Prim算法:设G=(V,E)是连通带权图,V={1,2,…,n}构造G的最小生成树的Prim算法的基本思想是:首先置S={1},然后,只要S是V的真子集,就作如下的贪心选择:选取满足条件iS,jV-S,且c[i][j]最小的边,将顶点j添加到S中。这个过程一直进行到S=V时为止。在这个过程中选取到的所有边恰好构成G的一棵最小生树。
三, 求最小生成树的Kruscal算法 对所有边从小到大排序;依次试探将边和它的端点加入生成树,如果加入此边后不产生圈,则将边和它的端点加入生成树;否则,将它删去;直到生成树中有了n-1条边,即告终止。算法的时间复杂度O(eloge) 将边按权值从小到大排序后逐个判断,如果当前的边加入以后不会产生环,那么就把当前边作为生成树的一条边。最终得到的结果就是最小生成树。并查集 。
总结,专题四主要的目的就是寻找最小生成树,求最短路径。这其中有两种算法:Prim算法和Kruscal算法。一个是选点,一个是选边。当题目中边的数目较为复杂时,选用prim算法。但是一般性问题时,建议选择kruscal算法,理解起来比较简单。
总结报告:
一学期的ACM课程就要结束,虽然是个选修课,感觉比专业课程还要重视。首先呢是自己对编程可比较感兴趣,看到一个难题,或者是实际的问题,用c++算法将它解决,并且在OJ上通过没有一点瑕疵,很有成就感。就好像高中做一道物理大题一样。老师讲解一个算法,首先根据老师的ppt的算法做出一道。然后再根据自己的理解解决其他的问题,没有比这更爽的了。最重要的一点是,确实能学到很多东西,不像有的课程一样,自己看看就能学会。第三点是,这门课确实让我思考了。有时候解决一道题就得想好长时间,并且得聚精会神。谁说上了大学就不用动脑了?学学acm吧。确实是锻炼了我的逻辑思维能力。 在这里也感谢费老师的耐心讲解。
以上是关于acm课程总结报告的主要内容,如果未能解决你的问题,请参考以下文章