当前位置:首页 » 操作系统 » acm算法模板

acm算法模板

发布时间: 2023-08-12 04:55:55

1. ACM题目求解题思路

有N个石子,每个石子重量Qi;按顺序将它们装进K个筐中;求一种方案,使得最重的筐最轻。 分析:本题乍一看很容易想到动态规划。事实上的确可以用动态规划解决,稍加分析我们很快得到一个简单的算法。用状态f(i,k)表示将前i个石子装入k个筐最优方案,g(i,j)表示i-j中最重的石子,则可以写出状态转移方程:g(i,j)=max {g(i,j-1),Qj}f(i,j)=min max {f(k , j-1), g(k+1 , i)} | 1<=j<=k边界条件:g(i,i)=Qi,f(1,1)=g(1,1)很明显,这个算法的时间复杂度为O(N3),空间复杂度为O(N2),并不十分理想。经过一些优化可以将复杂度降为O(N2),不过这样思维复杂度骤然加大,且算法本身仍不够高效。现在已经很难在原动态规划模型上做文章了,我们必须换一个思路。按一般的想法,顺序将石子装入筐,即先把石子放入第一筐,放到一定时候再改放第二个筐,第三个筐……但由于筐的重量没有上限,我们无法知道放到什么时候可以停止,转而将石子放入下一个筐。此时,问题的难点已经显露出来,是不是有方法可以化解呢?我们不妨针对上面的难点,加入一个参数P,改求一个判定可行解问题:每个筐石子重量和不能超过P,是否可以用K个筐装下所有石子。首先经过分析不难发现,如果当前筐的石子总重量为T1,即将处理的石子重量为T2,若T1+T2 ≤P,则我们仍将该石子放入当前框,这是显而易见的。由此可以得出贪心算法,按顺序把石子放进筐,若将石子放入当前筐后,筐的总重量不超过P,则继续处理下一个石子;若重量和超过P,则将该石子放入下一个筐,若此时筐的数目超过K,则问题无解,否则处理完所有石子后就找到了一个可行解。以上算法时间复杂度O(N),空间复杂度O(N),这都是理论的下界。现在我们已经解决了可行解问题,再回到原问题。是不是可以利用刚才的简化过的问题呢?答案是肯定的。一个最简单的想法是从小到大枚举P,不断尝试找最优解为P的方案(这就是刚才的可行解问题),直到找到此方案。这就是题目的最优解。估算一下上面算法的时间复杂度。令T=∑Qi,则最坏情况下需要枚举T次才能找到解,而每次判断的时间复杂度为O(N),因此总的时间复杂度为O(TN),故需要做进一步优化。下面考虑答案所在的区间。很明显,若我们可以找到一个总重量不超过P’的解,则我们一定能找到一个总重量不超过P’+1的解,也就是说,可行答案必定可以位于区间[q,+∞](其中q为本题最优解)。因此,我们自然而然的联想到了二分,具体方法为:在区间[1,T]内取中值m,若可以找到不超过m的方案,则尝试区间[1,m-1];若不能,尝试区间[m+1,T]。不断重复以上步骤即可找到问题的最优解。分析一下采用二分法后算法总的时间复杂度:由于每次除去一半的区间,则一共只需判断log2N次,而每次判断的时间复杂度为O(N),因此这个算法总的时间复杂度为O(NlgT)。一般而言,这个复杂度可以令人满意的,并且实际使用中效果非常好。但该复杂度同权值有关,不完全属于多项式算法,我们可以继续求得一个多项式算法(该算法与本文核心内容无关,只作简单探讨)。首先,此问题的答案必定为某一段连续石子的和,而段数不超过n2,因此,我们最多只要判断log2N2=2log2N次即可。现在新的问题是如何找到第m大的段。首先,以每个石子开头的所有段,例如:3 2 1 2,以2开头的所有段:2;2 1; 2 1 2, 由于每个石子的重量都大于0,因此总和一定是递增的。现在有n个递增段,如何快速的找到第k大的数呢?设各段长度为L1,L2,…,LN,中点分别为M1,M2,…,MN,我们每次询问各段中点的大小,若L1/2+L2/2+..+LN/2>k,则找到权值最大的中点,删去其后的数(下图中红色部分),否则找到权值最小的中点,删去其前面的部分(下图中黑色部分),可以证明删去的一定不是所求的数。 注:上图中每个各格子代表一个数。 由以上可知每次可以去掉某一段的1/2,因为有n段,故总共需要去O(Nlog2N)次,每次找最小最大值可以用堆实现,复杂度仅为O(lgN),因此总的时间复杂度为O(lg2N),而由上文我们知道找中值的操作总共有log2N次,故这个算法的时间复杂度为O(Nlg3N)。 至此我们终于得到了一个多项式级别的算法,当然这个算法实现起来比较麻烦,实际效果也不甚理想,不过具有一定的理论价值,在此不做过多讨论。 回顾本题解题过程,首先我们得到了一个动态规划算法,由于很难再提高其效率,因此我们另辟蹊径,寻求新的算法。在分析过程中我们发现由于筐的重量没有上限,因此很难确定将多少石子放入同一个筐内。为了解决此难点,我们加入了参数P,改求可行解问题。参数的加入实际上就是强行给筐定了一个上界。正是由于这无形之中多出的条件,使得问题立刻简单化,于是我们很自然的得到了贪心算法。而最终使用二分法降低了算法的时间复杂度,成功地解决了问题。 由上面的例子我们得到了此类解法的一般步骤,通常分为两步:Ⅰ.首先引入参数P,解决子问题:能否找到一个不优于P的方案Ⅱ.从小到大枚举P,判断是否有优于P的方案,直到找出原问题的最优解 一般地,参数搜索可以通过二分法或迭代降低时间复杂度,由于迭代法证明比较复杂,所以本文更多的讨论二分法。 这个方法的应用比较广泛,通常情况下和上例一样求最大(小)值尽量小(大)的题目都可以采用此方法,比如下面的例子。神秘的山:有n个队员攀登n个山峰,每个队员需要选择一个山峰,队员们攀登的山峰各不相同,要求最后一个登顶的队员用的时间尽量短。 分析:本问题分为两个部分解决:1.求出每个队员攀登到各个山峰所需的时间;2.找一个最优分配方案。 第一部分属于几何问题,我们可以枚举每个队员攀登山峰的位置再做简单的判断(题目规定攀登点必须为整点,这就为枚举提供了条件),这样就可求得队员们攀登上各个山峰所需的时间。下面重点讨论第二部分。首先将我们的数据构图,很明显,我们得到的是一个二部图,假设有3个队员3个山峰,每个队员攀登的时间如下 山峰1山峰2山峰3队员1132队员2222队员3133 则我们可以构图,每条边附上相应的权值: 现在的任务就是在图中找一个匹配,匹配中权值最大的边尽量小。这个问题是否可以直接套用一些常见的模型呢?比如最大匹配或是最佳匹配?经过分析不难发现在这个问题中它们都是不足以胜任的,因此我们不得不做新的尝试。 上文提到过要求极大(小)值尽量小(大)的题目往往先定出上界比较容易下手,那么这题也采用类似的思路。引入一个参数T,先求一个判定可行解的子问题:找一个方案,要求最后登山的队员所用时间不超过T。 改变后的题目有什么不同之处呢?如果队员i攀登上山峰j所需的时间超过T,则可以认为他在规定时间内不能攀登上山峰j,我们就可以把这条边从图中删去。例如在上例中找一个不超过2的方案,经过一次“筛选”,保留的图如下。 经过这次过滤保留下来的边都是“合法边”,我们只需要在这个新的二部图中找一个完备匹配即可,一个完备匹配唯一对应着一个可行方案。而找完备匹配可以借用最大匹配的算法,因为如果一个二部图的最大匹配数等于N,则找到了一个完备匹配,否则该图中将不存在完备匹配。(上图中的红色表示一个完备匹配),那么这一步的时间复杂度为O(NM),而在本题中M=N2,因此我们可以在O(N3)的时间内判断出是否存在一个方案满足最后等上山顶的队员时间不超过T。 最后,再用二分法枚举参数T,找到最优解。由于答案必定为某个队员攀登上其中一个山峰的时间,因此我们开始的时候可以将所有数据排序,这样最终的时间复杂度为O(N3lgN)。引入参数后求可行解的子问题与原问题最大的区别在于定下上界以后,我们很自然的排除了一些不可取条件,从而留下了“合法”条件,使得问题变的简单明了。. 上面的例子在增加了上界之后,排除了一些无效条件,其实它的作用绝不仅局限于此,有些时候,它能将不确定条件变为确定条件,比如下面的例子,最大比率问题:有N道题目,每道题目有不同的分值和难度,分别为Ai,Bi;要求从某一题开始, 至少连续选K道题目,满足分值和与难度和的比最大。 分析:最朴素的想法是枚举下标i’,j’,得到每一个长度不小于K的连续段,通过累加Ai’->Aj’,Bi’->Bj’求出比值,并找出比最大的一段。这样做的时间复杂度很高,由于总共有N2段,每次计算比值的时间是O(N),则总的时间复杂度到达O(N3),不过计算比值时,可以采用部分和优化,这样能把复杂度降至O(N2),但仍然不够理想。我们需要追求更出色的算法,先考虑一个简单的问题——不考虑难度(Bi),仅仅要求分值和最大(当然此时分值有正有负)。这个简化后的问题可以直接扫描,开始时为一个长度为K的段,设为Q1,Q2,…Qk, 每次添加一个新数,若Q1+Q2+..+QL-K小于0,则把它们从数列中删去,不断更新最优解即可。这样我们就能在O(N)的时间内找到长度不小于k且和最大的连续段。 之所以能成功解决简化后的问题,是由于该问题中每个量对最终结果的影响是确定的,若其小于0,则对结果产生不好的影响,反之则是有益的影响。那么原问题每个参数对最终结果的影响是不是确定的呢?很遗憾,并不是这样,因为每个题目有两个不同的参数,他们之间存在着某些的联系,而这些联系又具有不确定性,故我们很难知道它们对最终结果是否有帮助。想解决原问题,必须设法消除这个不确定因素!那么有没有办法将这些不确定的因素转化成确定的因素呢?此时,引入参数势在必行!那么我们引入参数P,求一个新的问题:找一个比值不小于P的方案。这个问题实际就是求两个下标i’,j’,满足下面两个不等式j’-i’+1≥k ①(Ai’+Ai’+1....+Aj’)/(Bi’+Bi’+1…+Bj’) ≥ p ②由不等式②=>Ai’+Ai’+1....+Aj’ ≥p(Bi’+Bi’+1…+Bj’)整理得(Ai’-pBi’)+(Ai’+1-pBi’+1)…+(Aj’-pBj’) ≥0可以令Ci=Ai-pBi,则根据上面不等式可知问题实际求一个长度不小于k且和大于0的连续段。由之前的分析可以知道我们能在O(N)的时间内求出长度不小于k且和最大的连续段,那么如果该段的和大于等于0,则我们找到了一个可行解,如果和小于0,则问题无解。也就是说,我们已经能在O(N)的时间内判断出是否存在比值不小于P的方案,那么接下来的步骤也就顺理成章了。我们需要通过二分法调整参数P,不断逼近最优解。计算一下以上算法的时间复杂度,设答案为T,则该算法的时间复杂度为O(NlgT),虽然这并不是多项式级别的算法,但在实际使用中的效果非常好。引入参数后,由于增加了一个条件,我们就可以将不确定的量变为确定的量,从而解决了问题。三. 总结 本文主要通过几个例子说明了参数搜索法在信息学中的应用,从上文的例子可以看出加入参数一方面能大大降低思维复杂度,另一方面也能得到效率相当高的算法,这使得我们解最解问题又多了一中有力的武器。当然,任何事物都是具有两面性的。参数搜索在具有多种优点的同时也有着消极的一面。由于需要不断调整参数逼近最优解,其时间复杂度往往略高于最优算法,且通常依赖于某个权值的大小,使得我们得到的有时不是严格意义上的多项式算法。文章中还总结了使用此方法解题的一般步骤,在实际应用中,我们不能拘泥于形式化的东西,必须灵活应用,大胆创新,这样才能游刃有余的解决问题。

2. acm竞赛知识点

1. acm常用小知识点
acm常用小知识点 1.ACM 关于ACM程序设计竞赛,需要掌握哪些知识点,最好能详细一
训练过ACM等程序设计竞赛的人在算法上有较大的优势,这就说明当你编程能力提高之后,主要时间是花在思考算法上,不是花在写程序与debug上。

下面给个计划你练练:第一阶段:练经典常用算法,下面的每个算法给我打上十到二十遍,同时自己精简代码,因为太常用,所以要练到写时不用想,10-15分钟内打完,甚至关掉显示器都可以把程序打出来。1.最短路(Floyd、Dijstra,BellmanFord) 2.最小生成树(先写个prim,kruscal要用并查集,不好写) 3.大数(高精度)加减乘除4.二分查找. (代码可在五行以内) 5.叉乘、判线段相交、然后写个凸包. 6.BFS、DFS,同时熟练hash表(要熟,要灵活,代码要简) 7.数学上的有:辗转相除(两行内),线段交点、多角形面积公式. 8. 调用系统的qsort, 技巧很多,慢慢掌握. 9. 任意进制间的转换第二阶段:练习复杂一点,但也较常用的算法。

如: 1. 二分图匹配(匈牙利),最小路径覆盖 2. 网络流,最小费用流。 3. 线段树. 4. 并查集。

5. 熟悉动态规划的各个典型:LCS、最长递增子串、三角剖分、记忆化dp 6.博弈类算法。博弈树,二进制法等。

7.最大团,最大独立集。 8.判断点在多边形内。

9. 差分约束系统. 10. 双向广度搜索、A*算法,最小耗散优先.第三阶段: 前两个阶段是打基础,第三阶段是锻炼在比赛中可以快速建立模型、想新算法。这就要平时多做做综合的题型了。

1. 把oibh上的论文看看(大概几百篇的,我只看了一点点,呵呵)。 2. 平时扫扫zoj上的难题啦,别老做那些不用想的题.(中大acm的版主经常说我挑简单的来做:-P ) 3. 多参加网上的比赛,感受一下比赛的气氛,评估自己的实力. 4. 一道题不要过了就算,问一下人,有更好的算法也打一下。

5. 做过的题要记好 :-)下面转自:ACMer必备知识(任重而道远。)

图论 路径问题 0/1边权最短路径 BFS 非负边权最短路径(Dijkstra) 可以用Dijkstra解决问题的特征 负边权最短路径 Bellman-Ford Bellman-Ford的Yen-氏优化 差分约束系统 Floyd 广义路径问题 传递闭包 极小极大距离 / 极大极小距离 Euler Path / Tour 圈套圈算法 混合图的 Euler Path / Tour Hamilton Path / Tour 特殊图的Hamilton Path / Tour 构造 生成树问题 最小生成树 第k小生成树 最优比率生成树 0/1分数规划 度限制生成树 连通性问题 强大的DFS算法 无向图连通性 割点 割边 二连通分支 有向图连通性 强连通分支 2-SAT 最小点基 有向无环图 拓扑排序 有向无环图与动态规划的关系 二分图匹配问题 一般图问题与二分图问题的转换思路 最大匹配 有向图的最小路径覆盖 0 / 1矩阵的最小覆盖 完备匹配 最优匹配 稳定婚姻 网络流问题 网络流模型的简单特征和与线性规划的关系 最大流最小割定理 最大流问题 有上下界的最大流问题 循环流 最小费用最大流 / 最大费用最大流 弦图的性质和判定组合数学 解决组合数学问题时常用的思想 逼近 递推 / 动态规划 概率问题 Polya定理计算几何 / 解析几何 计算几何的核心:叉积 / 面积 解析几何的主力:复数 基本形 点 直线,线段 多边形 凸多边形 / 凸包 凸包算法的引进,卷包裹法 Graham扫描法 水平序的引进,共线凸包的补丁 完美凸包算法 相关判定 两直线相交 两线段相交 点在任意多边形内的判定 点在凸多边形内的判定 经典问题 最小外接圆 近似O(n)的最小外接圆算法 点集直径 旋转卡壳,对踵点 多边形的三角剖分数学 / 数论 最大公约数 Euclid算法 扩展的Euclid算法 同余方程 / 二元一次不定方程 同余方程组 线性方程组 高斯消元法 解mod 2域上的线性方程组 整系数方程组的精确解法 矩阵 行列式的计算 利用矩阵乘法快速计算递推关系 分数 分数树 连分数逼近 数论计算 求N的约数个数 求phi(N) 求约数和 快速数论变换 …… 素数问题 概率判素算法 概率因子分解数据结构 组织结构 二叉堆 左偏树 二项树 胜者树 跳跃表 样式图标 斜堆 reap 统计结构 树状数组 虚二叉树 线段树 矩形面积并 圆形面积并 关系结构 Hash表 并查集 路径压缩思想的应用 STL中的数据结构 vector deque set / map动态规划 / 记忆化搜索 动态规划和记忆化搜索在思考方式上的区别 最长子序列系列问题 最长不下降子序列 最长公共子序列 最长公共不下降子序列 一类NP问题的动态规划解法 树型动态规划 背包问题 动态规划的优化 四边形不等式 函数的凸凹性 状态设计 规划方向线性规划常用思想 二分 最小表示法串 KMP Trie结构 后缀树/后缀数组 LCA/RMQ 有限状态自动机理论排序 选择/冒泡 快速排序 堆排序 归并排序 基数排序 拓扑排序 排序网络。
2.ACM需要具备什么知识
ACM国际大学生程序设计竞赛(ACM/ICPC :ACM International Collegiate Programming Contest)是由国际计算机界历史悠久、颇具权威性的组织ACM( 美国计算机协会)学会(Association for puter Machineary)主办,是世界上公认的规模最大、水平最高的国际大学生程序设计竞赛,其目的旨在使大学生运用计算机来充分展示自已分析问题和解决问题的能力。该项竞赛从1970年举办至今已历25届,因历届竞赛都荟萃了世界各大洲的精英,云集了计算机界的“希望之星”,而受到国际各知名大学的重视,并受到全世界各着名计算机公司如Microsoft(微软公司) 、IBM等的高度关注,成为世界各国大学生最具影响力的国际级计算机类的赛事,ACM所颁发的获奖证书也为世界各着名计算机公司、各知名大学所认可。

该项竞赛是年度性竞赛,分区域预赛和国际决赛两个阶段进行,各预赛区第一名自动获得参加世界决赛的资格,世界决赛安排在每年的3~4月举行,而区域预赛安排在上一年的9月~12月在各大洲举行。从1998年开始,IBM公司连续5年独家赞助该项赛事的世界决赛和区域预赛。这项比赛是以大学为单位组队(每支队由教练、3名正式队员,一名后备队员组成)参赛,要求在5个小时内,解决5~8到题目。

ACM/ICPC的区域预赛是规模很大,范围很广的赛事,近几年,全世界有1000多所大学, 2000多支参赛队在六大洲的28~30个赛站中争夺世界决赛的60~66个名额,去年我校举办的区域预赛,就有来自50多所高校的100多支队伍参加,其激烈程度可想而知。

与其他编程竞赛相比,ACM/ICPC题目难度更大,更强调算法的高效性,不仅要解决一个指定的命题,而且必需要以最佳的方式解决指定的命题;它涉及知识面广,与大学计算机系本科以及研究生如程序设计、离散数学、数据结构、人工智能、算法分析与设计等相关课程直接关联,对数学要求更高,由于采用英文命题,对英语要求高,ACM/ICPC采用3人合作、共用一台电脑,所以它更强调团队协作精神;由于许多题目并无现成的算法,需要具备创新的精神,ACM/ICPC不仅强调学科的基础,更强调全面素质和能力的培养。ACM/ICPC是一种全封闭式的竞赛,能对学生能力进行实时的全面的考察,其成绩的真实性更强,所以目前已成为内地高校的一个热点,是培养全面发展优秀人材的一项重要的活动。概括来说就是:强调算法的高效性、知识面要广、对数学和英语要求较高、团队协作和创新精神。
3.ACM需要那些方面的知识
一、语言是最重要的基本功 无论侧重于什么方面,只要是通过计算机程序去最终实现的竞赛,语言都是大家要 过的第一道关。

亚洲赛区的比赛支持的语言包括C/C++与JAVA。笔者首先说说JAVA,众所 周知,作为面向对象的王牌语言,JAVA在大型工程的组织与安全性方面有着自己独特的 优势,但是对于信息学比赛的具体场合,JAVA则显得不那么合适,它对于输入输出流的 操作相比于C++要繁杂很多,更为重要的是JAVA程序的运行速度要比C++慢10倍以上,而 竞赛中对于JAVA程序的运行时限却往往得不到同等比例的放宽,这无疑对算法设计提出 了更高的要求,是相当不利的。

其实,笔者并不主张大家在这种场合过多地运用面向对 象的程序设计思维,因为对于小程序来说这不旦需要花费更多的时间去编写代码,也会 降低程序的执行效率。 接着说C和C++。

许多现在参加讲座的同学还在上大一,C的基础知识刚刚学完,还没 有接触过C++,其实在赛场上使用纯C的选手还是大有人在的,它们主要是看重了纯C在效 率上的优势,所以这部分同学如果时间有限,并不需要急着去学习新的语言,只要提高 了自己在算法设计上的造诣,纯C一样能发挥巨大的威力。 而C++相对于C,在输入输出流上的封装大大方便了我们的操作,同时降低了出错的 可能性,并且能够很好地实现标准流与文件流的切换,方便了调试的工作。

如果有些同 学比较在意这点,可以尝试C和C++的混编,毕竟仅仅学习C++的流操作还是不花什么时间 的。 C++的另一个支持来源于标准模版库(STL),库中提供的对于基本数据结构的统一 接口操作和基本算法的实现可以缩减我们编写代码的长度,这可以节省一些时间。

但是 ,与此相对的,使用STL要在效率上做出一些牺牲,对于输入规模很大的题目,有时候必 须放弃STL,这意味着我们不能存在“有了STL就可以不去管基本算法的实现”的想法; 另外,熟练和恰当地使用STL必须经过一定时间的积累,准确地了解各种操作的时间复杂 度,切忌对STL中不熟悉的部分滥用,因为这其中蕴涵着许多初学者不易发现的陷阱。 通过以上的分析,我们可以看出仅就信息学竞赛而言,对语言的掌握并不要求十分 全面,但是对于经常用到的部分,必须十分熟练,不允许有半点不清楚的地方,下面我 举个真实的例子来说明这个道理——即使是一点很细微的语言障碍,都有可能酿成错误 : 在去年清华的赛区上,有一个队在做F题的时候使用了cout和printf的混合输出,由 于一个带缓冲一个不带,所以输出一长就混乱了。

只是因为当时judge team中负责F题的 人眼睛尖,看出答案没错只是顺序不对(答案有一页多,是所有题目中最长的一个输出 ),又看了看程序发现只是输出问题就给了个Presentation error(格式错)。如果审 题的人不是这样而是直接给一个 Wrong Answer,相信这个队是很难查到自己错在什么地 方的。

现在我们转入第二个方面的讨论,基础学科知识的积累。 二、以数学为主的基础知识十分重要 虽然被定性为程序设计竞赛,但是参赛选手所遇到的问题更多的是没有解决问题的 思路,而不是有了思路却死活不能实现,这就是平时积累的基础知识不够。

今年World Final的总冠军是波兰华沙大学,其成员出自于数学系而非计算机系,这就是一个鲜活的 例子。竞赛中对于基础学科的涉及主要集中于数学,此外对于物理、电路等等也可能有 一定应用,但是不多。

因此,大一的同学也不必为自己还没学数据结构而感到不知从何 入手提高,把数学捡起来吧!下面我来谈谈在竞赛中应用的数学的主要分支。 1、离散数学——作为计算机学科的基础,离散数学是竞赛中涉及最多的数学分支, 其重中之重又在于图论和组合数学,尤其是图论。

图论之所以运用最多是因为它的变化最多,而且可以轻易地结合基本数据结构和许 多算法的基本思想,较多用到的知识包括连通性判断、DFS和BFS,关节点和关键路径、欧拉回路、最小生成树、最短路径、二部图匹配和网络流等等。虽然这部分的比重很大 ,但是往往也是竞赛中的难题所在,如果有初学者对于这部分的某些具体内容暂时感到 力不从心,也不必着急,可以慢慢积累。

竞赛中设计的组合计数问题大都需要用组合数学来解决,组合数学中的知识相比于 图论要简单一些,很多知识对于小学上过奥校的同学来说已经十分熟悉,但是也有一些 部分需要先对代数结构中的群论有初步了解才能进行学习。组合数学在竞赛中很少以难 题的形式出现,但是如果积累不够,任何一道这方面的题目却都有可能成为难题。

2、数论——以素数判断和同余为模型构造出来的题目往往需要较多的数论知识来解 决,这部分在竞赛中的比重并不大,但只要来上一道,也足以使知识不足的人冥思苦想 上一阵时间。素数判断和同余最常见的是在以密码学为背景的题目中出现,在运用密码 学常识确定大概的过程之后,核心算法往往要涉及数论的内容。

3、计算几何——计算几何相比于其它部分来说是比较独立的,就是说它和其它的知 识点很少有过多的结合,较常用到的部分包括——线段相交的判断、多边形面积的计算 、内点外点的判断、凸包等。
4.ACM需要那些方面的知识
一、语言是最重要的基本功 无论侧重于什么方面,只要是通过计算机程序去最终实现的竞赛,语言都是大家要 过的第一道关。

亚洲赛区的比赛支持的语言包括C/C++与JAVA。笔者首先说说JAVA,众所 周知,作为面向对象的王牌语言,JAVA在大型工程的组织与安全性方面有着自己独特的 优势,但是对于信息学比赛的具体场合,JAVA则显得不那么合适,它对于输入输出流的 操作相比于C++要繁杂很多,更为重要的是JAVA程序的运行速度要比C++慢10倍以上,而 竞赛中对于JAVA程序的运行时限却往往得不到同等比例的放宽,这无疑对算法设计提出 了更高的要求,是相当不利的。

其实,笔者并不主张大家在这种场合过多地运用面向对 象的程序设计思维,因为对于小程序来说这不旦需要花费更多的时间去编写代码,也会 降低程序的执行效率。 接着说C和C++。

许多现在参加讲座的同学还在上大一,C的基础知识刚刚学完,还没 有接触过C++,其实在赛场上使用纯C的选手还是大有人在的,它们主要是看重了纯C在效 率上的优势,所以这部分同学如果时间有限,并不需要急着去学习新的语言,只要提高 了自己在算法设计上的造诣,纯C一样能发挥巨大的威力。 而C++相对于C,在输入输出流上的封装大大方便了我们的操作,同时降低了出错的 可能性,并且能够很好地实现标准流与文件流的切换,方便了调试的工作。

如果有些同 学比较在意这点,可以尝试C和C++的混编,毕竟仅仅学习C++的流操作还是不花什么时间 的。 C++的另一个支持来源于标准模版库(STL),库中提供的对于基本数据结构的统一 接口操作和基本算法的实现可以缩减我们编写代码的长度,这可以节省一些时间。

但是 ,与此相对的,使用STL要在效率上做出一些牺牲,对于输入规模很大的题目,有时候必 须放弃STL,这意味着我们不能存在“有了STL就可以不去管基本算法的实现”的想法; 另外,熟练和恰当地使用STL必须经过一定时间的积累,准确地了解各种操作的时间复杂 度,切忌对STL中不熟悉的部分滥用,因为这其中蕴涵着许多初学者不易发现的陷阱。 通过以上的分析,我们可以看出仅就信息学竞赛而言,对语言的掌握并不要求十分 全面,但是对于经常用到的部分,必须十分熟练,不允许有半点不清楚的地方,下面我 举个真实的例子来说明这个道理——即使是一点很细微的语言障碍,都有可能酿成错误 : 在去年清华的赛区上,有一个队在做F题的时候使用了cout和printf的混合输出,由 于一个带缓冲一个不带,所以输出一长就混乱了。

只是因为当时judge team中负责F题的 人眼睛尖,看出答案没错只是顺序不对(答案有一页多,是所有题目中最长的一个输出 ),又看了看程序发现只是输出问题就给了个Presentation error(格式错)。如果审 题的人不是这样而是直接给一个 Wrong Answer,相信这个队是很难查到自己错在什么地 方的。

现在我们转入第二个方面的讨论,基础学科知识的积累。 二、以数学为主的基础知识十分重要 虽然被定性为程序设计竞赛,但是参赛选手所遇到的问题更多的是没有解决问题的 思路,而不是有了思路却死活不能实现,这就是平时积累的基础知识不够。

今年World Final的总冠军是波兰华沙大学,其成员出自于数学系而非计算机系,这就是一个鲜活的 例子。竞赛中对于基础学科的涉及主要集中于数学,此外对于物理、电路等等也可能有 一定应用,但是不多。

因此,大一的同学也不必为自己还没学数据结构而感到不知从何 入手提高,把数学捡起来吧!下面我来谈谈在竞赛中应用的数学的主要分支。 1、离散数学——作为计算机学科的基础,离散数学是竞赛中涉及最多的数学分支, 其重中之重又在于图论和组合数学,尤其是图论。

图论之所以运用最多是因为它的变化最多,而且可以轻易地结合基本数据结构和许 多算法的基本思想,较多用到的知识包括连通性判断、DFS和BFS,关节点和关键路径、欧拉回路、最小生成树、最短路径、二部图匹配和网络流等等。虽然这部分的比重很大 ,但是往往也是竞赛中的难题所在,如果有初学者对于这部分的某些具体内容暂时感到 力不从心,也不必着急,可以慢慢积累。

竞赛中设计的组合计数问题大都需要用组合数学来解决,组合数学中的知识相比于 图论要简单一些,很多知识对于小学上过奥校的同学来说已经十分熟悉,但是也有一些 部分需要先对代数结构中的群论有初步了解才能进行学习。组合数学在竞赛中很少以难 题的形式出现,但是如果积累不够,任何一道这方面的题目却都有可能成为难题。

2、数论——以素数判断和同余为模型构造出来的题目往往需要较多的数论知识来解 决,这部分在竞赛中的比重并不大,但只要来上一道,也足以使知识不足的人冥思苦想 上一阵时间。素数判断和同余最常见的是在以密码学为背景的题目中出现,在运用密码 学常识确定大概的过程之后,核心算法往往要涉及数论的内容。

3、计算几何——计算几何相比于其它部分来说是比较独立的,就是说它和其它的知 识点很少有过多的结合,较常用到的部分包括——线段相交的判断、多边形面积的计算 、内点外点的判断、凸包等。
5.ACM需要具备什么知识
ACM国际大学生程序设计竞赛(ACM/ICPC :ACM International Collegiate Programming Contest)是由国际计算机界历史悠久、颇具权威性的组织ACM( 美国计算机协会)学会(Association for puter Machineary)主办,是世界上公认的规模最大、水平最高的国际大学生程序设计竞赛,其目的旨在使大学生运用计算机来充分展示自已分析问题和解决问题的能力。该项竞赛从1970年举办至今已历25届,因历届竞赛都荟萃了世界各大洲的精英,云集了计算机界的“希望之星”,而受到国际各知名大学的重视,并受到全世界各着名计算机公司如Microsoft(微软公司) 、IBM等的高度关注,成为世界各国大学生最具影响力的国际级计算机类的赛事,ACM所颁发的获奖证书也为世界各着名计算机公司、各知名大学所认可。

该项竞赛是年度性竞赛,分区域预赛和国际决赛两个阶段进行,各预赛区第一名自动获得参加世界决赛的资格,世界决赛安排在每年的3~4月举行,而区域预赛安排在上一年的9月~12月在各大洲举行。从1998年开始,IBM公司连续5年独家赞助该项赛事的世界决赛和区域预赛。这项比赛是以大学为单位组队(每支队由教练、3名正式队员,一名后备队员组成)参赛,要求在5个小时内,解决5~8到题目。

ACM/ICPC的区域预赛是规模很大,范围很广的赛事,近几年,全世界有1000多所大学, 2000多支参赛队在六大洲的28~30个赛站中争夺世界决赛的60~66个名额,去年我校举办的区域预赛,就有来自50多所高校的100多支队伍参加,其激烈程度可想而知。

与其他编程竞赛相比,ACM/ICPC题目难度更大,更强调算法的高效性,不仅要解决一个指定的命题,而且必需要以最佳的方式解决指定的命题;它涉及知识面广,与大学计算机系本科以及研究生如程序设计、离散数学、数据结构、人工智能、算法分析与设计等相关课程直接关联,对数学要求更高,由于采用英文命题,对英语要求高,ACM/ICPC采用3人合作、共用一台电脑,所以它更强调团队协作精神;由于许多题目并无现成的算法,需要具备创新的精神,ACM/ICPC不仅强调学科的基础,更强调全面素质和能力的培养。ACM/ICPC是一种全封闭式的竞赛,能对学生能力进行实时的全面的考察,其成绩的真实性更强,所以目前已成为内地高校的一个热点,是培养全面发展优秀人材的一项重要的活动。概括来说就是:强调算法的高效性、知识面要广、对数学和英语要求较高、团队协作和创新精神。
6.ACM常用的经典算法
大概分为数论算法,图论算法,A*算法。

数论算法:

排序(选择,冒泡,快速,归并,堆,基数,桶排序等)

递归,回溯

概率,随机

公约数,素数

因数分解

矩阵运算

线性规划

最小二乘

微积分

多项式分解和级数

图论算法:

哈夫曼树(即最优二叉树)

哈希表

Prim,Kruskal算法(即最小生成树算法)

红黑树

a-B剪枝法

深、广度搜索

拓扑排序

强连通分量

Dijkstra,Bellman-Ford,Floyd-Warashall算法(最短路径算法)

计算几何(线段相交,凸包,最近点对)

A*算法:

动态规划

贪心算法

KMP算法

哈密顿回路问题

子集问题

博弈(极大极小值算法等)
7.参加ACM需要准备哪些知识
学ACM要熟练C语言的基础语法,对编程有很大的兴趣,还要学关于数据结构的知识。

内容大多数是考数据结构,例如:深度搜索(dfs)、广度搜索(bfs)、并查集、母函数、最小生成树、数论、动态规划(重点)、背包问题、最短路、网络流……还有很多算法,我列出这些是经常考到的,我也在学习上述所说的。 最好买一本《数据结构》或者关于算法的书看看,看完一些要自己动手实践做题,做题的话去杭电acm做题,里面有很多很基础的题,不错的。

资料的话,网络有很多,我多数都是网络或者 *** ,还有可以看看别人的博客的解题报告,里面有详细的介绍,不懂还可以问问同学师兄的。 对了,还有一点,acm比赛都是英文题目的,比赛时带本字典查吧。

希望我说的你能满意,祝你能在acm方面有所收获。

3. acm总是超时,有简单算法吗

当然有,首先求整除9的个数不需要一个个试,求含有9的也可以按位数递归。
//求某个正整数中,小于自身,且含有数字9或能被9整除的正整数的个数。
/*思路分析:
求含有数字9的总数 + 能被9整除的总数 - 既含有数字9又能被9整除的个数
具体思路:从高位到低位求含有数字9的范围 - 此范围内能被9整除的个数
还要 + 此范围外的低位范围内的结果(进行递归调用),
最后加上所有能被9整除的正整数个数。
如此可将大整数n划分
*/
如下图我先写求整除9的函数,为保证字函数正确性,写了一个暴力算法进行比对。如下图

#include<iostream>
usingnamespacestd;
#include<stdlib.h>
#include<time.h>
//求某个正整数中,小于自身,且含有数字9或能被9整除的正整数的个数。
/*思路分析:
求含有数字9的总数+能被9整除的总数-既含有数字9又能被9整除的个数
具体思路:从高位到低位求含有数字9的范围-此范围内能被9整除的个数
还要+此范围外的低位范围内的结果(进行递归调用),
最后加上所有能被9整除的正整数个数。
如此可将大整数n划分
*/
//暴力验证算法
intsumOfDivided9_B(inta,intb){ //求介于a到b(不含b)之间的能被9整除的个数
intsum=0;
for(;a<b;a++){ //暴力算法做验证
if(0==a%9)sum++;
}returnsum;
}
//求介于a到b(不含b)之间的能被9整除的个数,(用户需保证a<b)
intsumOfDivided9(constint&a,constint&b){
return(b-1)/9-(a-1)/9; //即1~b-1减去1~a-1
}
intmain(){
srand(time(0)); //随机数种子
intcount=0; //错误的个数
for(inti=0;i<100;i++){
inta=rand(),b=a+1+rand()%10000; //随机生成范围,最多10000个数
intsum_B=sumOfDivided9_B(a,b); //暴力算法
intsum_Q=sumOfDivided9(a,b); //快速算法
if(sum_B!=sum_B){
cout<<"WRONG! ";
count++;
}elsecout<<"RIGHT√ ";
cout<<"(a="<<a<<")%9="<<a%9<<" (b="<<b<<")%9="<<b%9<<
" 暴力="<<sum_B<<" 快速="<<sum_Q<<endl;
}
cout<<"WRONGtotal="<<count<<endl;
system("pause");
}

未完待续!

4. 我是用的是C语言,想在黑龙江省ACM大赛中拿三等奖,应该掌握那些算法……

当中有几百种计算机常用的算法的框架和模板,如果你还在为算法问题而困扰时,这资料会让你廓然开朗,我也在学,很有用所以极力推荐给你.

框架部分目录如下:

图论

路径问题

0/1边权最短路径

BFS

非负边权最短路径(Dijkstra)

可以用Dijkstra解决问题的特征

负边权最短路径

Bellman-Ford

Bellman-Ford的Yen-氏优化

差分约束系统

Floyd

广义路径问题

传递闭包

极小极大距离/极大极小距离

EulerPath/Tour

圈套圈算法

混合图的EulerPath/Tour

HamiltonPath/Tour

特殊图的HamiltonPath/Tour构造

生成树问题

最小生成树

第k小生成树

最优比率生成树

0/1分数规划

度限制生成树

连通性问题

强大的DFS算法

无向图连通性

割点

割边

二连通分支

有向图连通性

强连通分支

2-SAT

最小点基

有向无环图

拓扑排序

有向无环图与动态规划的关系

二分图匹配问题

一般图问题与二分图问题的转换思路

最大匹配(OK)

有向图的最小路径覆盖

0/1矩阵的最小覆盖

完备匹配(OK)

最优匹配(OK)

稳定婚姻

网络流问题

网络流模型的简单特征和与线性规划的关系

最大流最小割定理

最大流问题(OK)

有上下界的最大流问题

循环流

最小费用最大流/最大费用最大流

弦图的性质和判定


组合数学

解决组合数学问题时常用的思想

逼近

递推/动态规划

概率问题

Polya定理


计算几何/解析几何

计算几何的核心:叉积/面积

解析几何的主力:复数

基本形

直线,线段

多边形

凸多边形/凸包

凸包算法的引进,卷包裹法

Graham扫描法

水平序的引进,共线凸包的补丁

完美凸包算法

相关判定

两直线相交

两线段相交

点在任意多边形内的判定

点在凸多边形内的判定

经典问题

最小外接圆

近似O(n)的最小外接圆算法

点集直径

旋转卡壳,对踵点

多边形的三角剖分


数学/数论

高精度计算

高数度加减法、乘除法

最大公约数

Euclid算法

扩展的Euclid算法

同余方程/二元一次不定方程

同余方程组

线性方程组

高斯消元法

解mod2域上的线性方程组

整系数方程组的精确解法

矩阵

行列式的计算

利用矩阵乘法快速计算递推关系

分数

分数树

连分数逼近

数论计算

求N的约数个数

求phi(N)

求约数和

快速数论变换

……

素数问题

概率判素算法

概率因子分解


数据结构

组织结构

二叉堆

左偏树

二项树

胜者树

跳跃表

样式图标

斜堆

reap

统计结构

树状数组

虚二叉树

线段树

矩形面积并

圆形面积并

关系结构

Hash表

并查集

路径压缩思想的应用

STL中的数据结构

vector

deque

set/map


动态规划/记忆化搜索

动态规划和记忆化搜索在思考方式上的区别

最长子序列系列问题

最长不下降子序列

最长公共子序列

一类NP问题的动态规划解法

树型动态规划

背包问题

动态规划的优化

四边形不等式

函数的凸凹性

状态设计

规划方向


线性规划

常用思想

二分

最小表示法

KMP

Trie结构

后缀树/后缀数组

LCA/RMQ

有限状态自动机理论

排序

选择/冒泡

快速排序

堆排序

归并排序(OK)

基数排序

拓扑排序

排序网络


5. acm竞赛的算法总共有那些范围 求大牛概括......

初级:
一.基本算法:
(1)枚举. (poj1753,poj2965)
(2)贪心(poj1328,poj2109,poj2586)
(3)递归和分治法.
(4)递推.
(5)构造法.(poj3295)
(6)模拟法.(poj1068,poj2632,poj1573,poj2993,poj2996)
二.图算法:
(1)图的深度优先遍历和广度优先遍历.
(2)最短路径算法(dijkstra,bellman-ford,floyd,heap+dijkstra)
(poj1860,poj3259,poj1062,poj2253,poj1125,poj2240)
(3)最小生成树算法(prim,kruskal)
(poj1789,poj2485,poj1258,poj3026)
(4)拓扑排序 (poj1094)
(5)二分图的最大匹配 (匈牙利算法) (poj3041,poj3020)
(6)最大流的增广路算法(KM算法). (poj1459,poj3436)
三.数据结构.
(1)串 (poj1035,poj3080,poj1936)
(2)排序(快排、归并排(与逆序数有关)、堆排) (poj2388,poj2299)
(3)简单并查集的应用.
(4)哈希表和二分查找等高效查找法(数的Hash,串的Hash)
(poj3349,poj3274,POJ2151,poj1840,poj2002,poj2503)
(5)哈夫曼树(poj3253)
(6)堆
(7)trie树(静态建树、动态建树) (poj2513)
四.简单搜索
(1)深度优先搜索 (poj2488,poj3083,poj3009,poj1321,poj2251)
(2)广度优先搜索(poj3278,poj1426,poj3126,poj3087.poj3414)
(3)简单搜索技巧和剪枝(poj2531,poj1416,poj2676,1129)
五.动态规划
(1)背包问题. (poj1837,poj1276)
(2)型如下表的简单DP(可参考lrj的书 page149):
1.E[j]=opt{D[i]+w(i,j)} (poj3267,poj1836,poj1260,poj2533)
2.E[i,j]=opt{D[i-1,j]+xi,D[i,j-1]+yj,D[i-1][j-1]+zij} (最长公共子序列)
(poj3176,poj1080,poj1159)
3.C[i,j]=w[i,j]+opt{C[i,k-1]+C[k,j]}.(最优二分检索树问题)
六.数学
(1)组合数学:
1.加法原理和乘法原理.
2.排列组合.
3.递推关系.
(POJ3252,poj1850,poj1019,poj1942)
(2)数论.
1.素数与整除问题
2.进制位.
3.同余模运算.
(poj2635, poj3292,poj1845,poj2115)
(3)计算方法.
1.二分法求解单调函数相关知识.(poj3273,poj3258,poj1905,poj3122)
七.计算几何学.
(1)几何公式.
(2)叉积和点积的运用(如线段相交的判定,点到线段的距离等). (poj2031,poj1039)
(3)多边型的简单算法(求面积)和相关判定(点在多边型内,多边型是否相交)
(poj1408,poj1584)
(4)凸包. (poj2187,poj1113)

6. 怎样求大组合数(取模)(ACM算法)

这种题目然做过的,
意思比较简单,就由 m 个共 0 和 n 个 1 组成一个串,但从左到右要1出现的次数不少于0出现的次数。
由大牛的算法: 结果就是 C(m+n, n) - C(m+n, m-1) 再取模,我们可以对式子化简一下就是:
(n+m)!*
(n-m+1) / ((m)!* (n+1)!)
再取模,但由于组合数很大,直接用大数乘除就会超时了,看了别人的报告才知道原来可以用素数化简快速求模的, n! = 2^p[i] *
3^p[i] * 5^p[i]*...... 再求模就可以很快了~(^ = ^)~。。。

#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
#define M 2000005
#define mm 20100501
bool sig[M];
int prime[150000], p[150000], len; // prime 记录素数, p 记录素数的幂 len 记录长度
void getprime() // 筛法找素数
{
int i,j,k=0;
prime[k++] = 2;
for(i=3; i<=M; i+=2)
{
if( !sig[i] )
{
prime[k++] = i;
for(j=i; j<=M; j+=i)
sig[j] = 1;
}
}
}
void get(int k, int s) // K! 的素数分解, S为指数的加减(分母,分子)
{
int i, mid;
for(i=0; prime[i]<=k && prime[i]; i++)
{
mid = k;
while(mid)
{
if(s)
p[i] += mid/prime[i];
else
p[i] -= mid/prime[i];
mid /= prime[i];
}
}
if(len < i)
len = i;
}
__int64 cal() // 计算结果 (prime[i...]^p[i...]) % mm
{
__int64 i,ans = 1;
for(i=0; i<=len; i++)
{
if( p[i] )
{
__int64 t = prime[i], b = p[i], ret = 1;
while(b) //计算 (t^b) % mm
{
if(b%2) ret *= t %mm;
t = t*t%mm;
b /= 2;
}
ans = ( ans*ret ) % mm;
}
}
return ans;
}
int main()
{
int t,m,n,i,mid;
__int64 ans;
getprime();
cin>>t;
while(t--)
{
cin>>n>>m;
len = 0;
memset(p, 0, sizeof(p));
mid = n-m+1; //先前要把 n-m+1 的因子加进 P 中去才能使 (m+n)! / ((m)!*(n+1)!) 整除
for(i=0; mid>1; i++)
{
if( mid%prime[i] == 0)
{
while(mid%prime[i]==0)
{
p[i] += 1;
mid /= prime[i];
}
}
}
get(m+n, 1);
get(m, 0);
get(n+1, 0);
ans = cal();
printf("%I64d\n", ans);
}
return 0;
}

可以用素数分解法,
先求出上面和下面的素数表示,然后约分后,再用求幂公式

热点内容
网易我的世界如何登陆服务器 发布:2025-03-11 06:23:22 浏览:713
用电脑玩逆战连接服务器很久 发布:2025-03-11 06:13:18 浏览:181
天翼智能路由器的初始密码是多少 发布:2025-03-11 06:10:17 浏览:914
安卓机怎么领岭南通 发布:2025-03-11 05:56:54 浏览:132
求生之路2虐电脑服务器 发布:2025-03-11 05:35:40 浏览:632
编译学堂 发布:2025-03-11 05:31:06 浏览:185
苹果文件夹隐藏 发布:2025-03-11 05:26:42 浏览:546
短信设置密码如何关闭 发布:2025-03-11 05:26:39 浏览:915
re管理器主文件夹 发布:2025-03-11 05:26:37 浏览:714
手机优酷缓存在哪 发布:2025-03-11 05:25:58 浏览:434