ACM学习总结

                                  Acm总结报告
  与acm程序设计这门课的接触是从大一上学期学校举办的面向大一新生的程序设计比赛,当时虽然什么也不会,只会简单的c++与c语言,当时学过的最复杂的程序就是冒泡排序了,现在回想起来还真是有趣,只是凭着一点兴趣就去参加了这个比赛,现在想来,如果不是那点兴趣我也不会接触到这一门课,当时比寒结束然后几位学长便在上面给我们介绍了他们 学习历程,然后留下了QQ群的号码,然后加入QQ群,在寒假的期间简单接触了关于acm 一点知识,当时还不知道acm是什么,上网查了后才知道是ACM国际大学生程序设计竞赛,而且还是由美国计算机协会主办的,瞬间便感觉这门课非常的高大上,但也有些怀疑自己能否学习这门高大上的课程,于是便抱着试试的态度来进行了一系列的学习。在寒假的期间仅仅是了解了一些基体的知识,然后学习了STL,STL是一个标准模板库,里面有许多的实用的容器,比如说 vector还有map以及在以后用到的队列以及核等等,还有就是包含了许多实用的算法,比如常用的sort包含在头文件< algorithm>。
   STL内容:
Vectors: 
将元素置于一个动态数组中加以管理,可以随机存取元素(用索引直接存取),数组尾部添加或移除元素非常快速。但是在中部或头部安插元素比较费时;
Deques: 
是“double-ended queue”的缩写,可以随机存取元素(用索引直接存取),数组头部和尾部添加或移除元素都非常快速。但是在中部或头部安插元素比较费时;
Lists:双向链表,不提供随机存取(按顺序走到需存取的元素,O(n)),在任何位置上执行插入或删除动作都非常迅速,内部只需调整一下指针;
2)关联式容器(Associated containers),元素位置取决于特定的排序准则,和插入顺序无关, 
set、multiset、map、multimap;
Sets/Multisets:内部的元素依据其值自动排序,Set内的相同数值的元素只能出现一次,Multisets内可包含多个数值相同的元素,内部由二叉树实现(实际上基于红黑树(RB-tree)实现),便于查找;
Maps/Multimaps:Map的元素是成对的键值/实值,内部的元素依据其值自动排序,Map内的相同数值的元素只能出现一次,Multimaps内可包含多个数值相同的元素,内部由二叉树实现(实际上基于红黑树(RB-tree)实现),便于查找;
  而后是学习了递归与递推,递归与递推算法就是在知道几个结果的时候,能够通过一种关系来推出其他的结果,然后通过循环来解决问题。递归算法的基本思想是:把规模大的、较难解决的问题变成规模较小的、易解决的同一问题。规模较小的问题又变成规模更小的问题,并且小到一定程度可以直接得出它的解,从而得到原来问题的解。我们利用递归算法解题,首先要对问题的以下三个方面进行分析: 
  1.决定问题规模的参数。需要用递归算法解决的问题,其规模通常都是比较大的,在问题中决定规模大小(或问题复杂程度)的量有哪些?把它们找出来。 
  2.问题的边界条件及边界值(又叫结束条件或出口)。在什么情况下可以直接得出问题的解?这就是问题的边界条件及边界值。 
  3.解决问题的通式(又叫递归体)。把规模大的、较难解决的问题变成规模较小、易解决的同一问题,需要通过哪些步骤或等式来实现?这是解决递归问题的难点。
  而后是动态规划问题,在刚开始学习动态规划的问题的时候感觉是学的一脸懵逼,感觉什么都不懂,上课的时候听得懵懵懂懂,然后回去的时候看了好长时间的解析才弄懂一些最简单的问题,好在在费了好多时间后终于弄懂了技巧。动态规划是解决多阶段决策问题的一种方法。多阶段决策问题是说如果一类问题的求解过程可以分为若干个互相联系的阶段,在每一个阶段都需作出决策,并影响到下一个阶段的决策。多阶段决策问题,就是要在可以选择的那些策略中间,选取一个最优策略,使在预定的标准下达到最好的效果。 
动态规划的指导思想就是在做每一步决策时,列出各种可能的局部解;依据某种判定条件,舍弃那些肯定不能得到最优解的局部解;以每一步都是最优的来保证全局是最优的。 
动态规划问题具有以下基本特征: 
问题具有多阶段决策的特征; 
每一阶段都有相应的“状态”与之对应,描述状态的量称为“状态变量”; 
每一阶段都面临一个决策,选择不同的决策将会导致下一阶段不同的状态; 
每一阶段的最优解问题可以递归地归结为下一阶段各个可能状态的最优解问题,各子问题与原问题具有完全相同的结构。在我看来,动态规划最重要的是写出状态转移方程,只要写出状态转移方程,一切便迎刃而解,顺着思路走,把每一个细致的地方弄懂,就能解决问题。
  动态规划例子:0-1背包问题
  问题描述:一共n中物品,每样物品只有一件,物品i的重量为wi>0,价值为vi,背包的最终容量为weight,求如何添加物品,在不超过背包容量的情况下,背包中物品的价值最大?
  状态转移方程:dp[j] = max{dp[j], dp[j-w[i]]+v[i]}, 其中1=<i<=n, w[i]<=j<=weight. dp[j]表示背包中重量为j时的最大价值。
  代码:
int main()
{
    cin>>n>>v;
    for(int i=1; i<=n; i++)
        cin>>c[i];
    for(int i=1; i<=n; i++)
        cin>>w[i];
    for(int i=1; i<=n; i++)
        f[i][0]=0;
    for(int i=1; i<=n; i++)
        for(int j=1; j<=v; j++)
            if(j>=w[i])
                f[i][j]=max(f[i-1][j-w[i]]+c[i],f[i-1][j])
                       else
                           f[i][j]=f[i-1][j];
    cout<<f[n][v]<<endl;
    return 0;
}
  贪心算法:(又称贪婪算法)
  是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解。
贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择,选择的贪心策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。贪心算法就是在解决一些选择当前状态下的最优解就能够导致最终的最优的问题的方法。
  贪心算法的基本思路:
    1.建立数学模型来描述问题。
    2.把求解的问题分成若干个子问题。
    3.对每一子问题求解,得到子问题的局部最优解。
    4.把子问题的解局部最优解合成原来解问题的一个解。
  贪心算法的最常见的一个例题就是可以用贪心算法解决01背包问题,虽然局限非常大,但是也是可以解决的。
  而后是二分查找法,二分查找又称折半查找,优点是比较次数少,查找速度快,平均性能好;其缺点是要求待查表为有序表,且插入删除困难。因此,折半查找方法适用于不经常变动而查找频繁的有序列表。首先,假设表中元素是按升序排列,将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功;否则利用中间位置记录将表分成前、后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。
  二分查找可以十分快速的寻找到答案,因为时间复杂度为log2(n),有许多问题都可以用二分查找来优化,从而避免tle的出现。
  二分查找的一个简单例题:输入n个数,然后输入一个数,输出该数在n个数中的位置。
  这个题我们可以用结构体或者map来分别储存位置与大小,然后按大小排序,然后二分查找。
  二分查找部分代码:
  while(1)
    {
    mid=(top+deep)/2;
    if(a[mid].x==s)
        break;
    if(a[mid].x>s)
        top=mid;
    else
        deep=mid;
    }
  cout<<a[i].y<<endl;
  在往后则是搜索,搜索这一章我感觉十分有趣,搜索包括三大类,其中有二分搜索,也就是前面写的二分查找,还有就是广度优先搜索以及深度优先搜索,也就是BFS与DFS。
  广度优先搜索(BFS):
  图的广度优先遍历BFS算法是一个分层搜索的过程,和树的层序遍历算法类同,它也需要一个队列以保持遍历过的顶点顺序,以便按出队的顺序再去访问这些顶点的邻接顶点。
2.基本实现思想
(1)顶点v入队列。
(2)当队列非空时则继续执行,否则算法结束。
(3)出队列取得队头顶点v;访问顶点v并标记顶点v已被访问。
(4)查找顶点v的第一个邻接顶点col。
(5)若v的邻接顶点col未被访问过的,则col入队列。
(6)继续查找顶点v的另一个新的邻接顶点col,转到步骤(5)。
        直到顶点v的所有未被访问过的邻接点处理完。转到步骤(2)。
广度优先遍历图是以顶点v为起始点,由近至远,依次访问和v有路径相通而且路径长度为1,2,……的顶点。为了使“先被访问顶点的邻接点”先于“后被访问顶点的邻接点”被访问,需设置队列存储访问的顶点。
  深度优先搜索(DFS):
  假设给定图G的初态是所有顶点均未曾访问过。在G中任选一顶点v为初始出发点(源点),则深度优先遍历可定义如下:首先访问出发点v,并将其标记为已访问过;然后依次从v出发搜索v的每个邻接点w。若w未曾访问过,则以w为新的出发点继续进行深度优先遍历,直至图中所有和源点v有路径相通的顶点(亦称为从源点可达的顶点)均已被访问为止。若此时图中仍有未访问的顶点,则另选一个尚未访问的顶点作为新的源点重复上述过程,直至图中所有顶点均已被访问为止。
  图的深度优先遍历类似于树的前序遍历。采用的搜索方法的特点是尽可能先对纵深方向进行搜索。这种搜索方法称为深度优先搜索(Depth-First Search)。相应地,用此方法遍历图就很自然地称之为图的深度优先遍历
2.基本实现思想:
(1)访问顶点v;
(2)从v的未被访问的邻接点中选取一个顶点w,从w出发进行深度优先遍历;
(3)重复上述两步,直至图中所有和v有路径相通的顶点都被访问到。
  二叉树:
  二叉树是每个节点最多有两个子树的树结构。通常子树被称作“左子树”(left subtree)和“右子树”(right subtree)。二叉树常被用于实现二叉查找树和二叉堆。
二叉树的每个结点至多只有二棵子树(不存在度大于2的结点),二叉树的子树有左右之分,次序不能颠倒。二叉树的第i层至多有2^{i-1}个结点;深度为k的二叉树至多有2^k-1个结点;对任何一棵二叉树T,如果其终端结点数为n_0,度为2的结点数为n_2,则n_0=n_2+1。
一棵深度为k,且有2^k-1个节点称之为满二叉树;深度为k,有n个节点的二叉树,当且仅当其每一个节点都与深度为k的满二叉树中,序号为1至n的节点对应时,称之为完全二叉树。
  图论:
  图论〔Graph Theory〕是数学的一个分支。它以图为研究对象。图论中的图是由若干给定的点及连接两点的线所构成的图形,这种图形通常用来描述某些事物之间的某种特定关系,用点代表事物,用连接两点的线表示相应两个事物间具有这种关系。
  学习的图论的重要问题也就是最小生成树问题了,最小生成树性质:设G=(V,E)是一个连通网络,U是顶点集V的一个非空真子集。若(u,v)是G中一条“一个端点在U中(例如:u∈U),另一个端点不在U中的边(例如:v∈V-U),且(u,v)具有最小权值,则一定存在G的一棵最小生成树包括此边(u,v)。
  解决最小生成树有两个算法,分别是Kruskal算法与Prim算法。
  图论这一章感觉自己还没有学好,许多的知识点还没有掌握,因此还是需要学习啊。
  经过了本学期的学习,也参加了比赛,虽然自己并没有做出什么成绩,但是却感觉这一学期十分充实,做了自己想做的事情,感受到了程序的奇妙,虽然偶尔也会感到有些枯燥,但总的来说是值得的,最后也感谢老师一学期详细而耐心的教导。
  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值