1. 逗号表达式
在“计蒜客“的ACM教程中,看到这样一段很好的代码:
int n;
while (scanf("%d", &n), n) {
//do something
}
解释如下:
scanf后面有个逗号,这就是所谓的逗号表达式。整个表达式的结果就是用逗号分隔的最后一个表达式的值。当n的值为0时,整个表达式的值就是0,此时退出循环。
2. ACM惯用头文件
引用
#include <bits/stdc++.h>
而无需引用两个头文件
#include <iostream>
#include <cstdio>
这种方法并不是所有平台都适用的,用之前记得查阅平台的FAQ。不过在国内oj中,poj,hdu 不支持这个函数,这几个oj的编译器问题,其他国外的oj,还有*的oj都支持,CF(http://codeforces.com/),Topcoder也都支持。
3. 读取一整行字符串——scanf 与 gets
输入样本如下:
I promise I will no more cheat in tests.
2
1
在这里
scanf("%s", str);
是行不通的,因为文章——第一行的字符串——的内部会有空格,而这样的语句只能把空格之前的内容读入到str。
因此我们要使用读取一整行的函数,如下:
gets(str);
多提醒读者一句,使用gets的时候如果发生溢出的话程序是不会报错的,所以读者在使用gets的时候一定要小心哦!
4. 判断输入结束——scanf 函数
while (scanf("%d", &cnt) == ) {
//do something
}
当scanf正确读入时,返回值是和读取的变量数目相等的。而当读取出错、读到文件末尾时,scanf函数会返回-1,因此当读到文件结束时,上述while循环就会中止。当然啦,也可以写成如下样式,效果是等价的。
while (scanf("%d", &cnt) != -){
//do something
}
5. int不够用时——long long类型
输入数据的范围最大是10000,10000的立方是10^12,而int类型的最大值是2147483647,大约是2*10^9,远远超过了int的最大值,这样在计算过程中就会出现溢出的情况,导致结果错误。因此我们需要用更大的整数类型long long,它的最大值大约为10^19,即使10000个10^12也不会超过long long的取值范围。
此外,记得long long输出是用%lld而非%d哦。
6. 关于Bug
做题时不可避免会遇到程序错误(Bug),这时程序会在Online Judge上获得对应的错误信息,比如Wrong Answer, Runtime Error等。此时就需要各种debug方法来解决。通常debug有三类方法:通读程序;重读题目和使用数据调试。
循环自增变量笔误是常见的bug,多见于多重循环的内层中。
7. 编程比赛
Topcoder也是唯一一个必须下载客户端才能参加的程序设计竞赛。用户在Topcoder会有积分(rating)和积分对应的颜色标示,如上图中所 示,红>黄>蓝>绿>灰>白。积分最高的几个选手的id左侧会有一个类似靶心的标志,我们称之为target。 ACRush(楼天城)就是target选手之一。
在 Linux上与mingw对应的是gcc和g++,由于这些都是系统自带的程序,在安装Codeblocks的时候不需要再单独安装一遍了。两个编译器在 一些细微之处还是有不同的,比如64位整型变量的输入(scanf)和输出(printf),在Linux下参数为%lld,而Windows下的参数 为%I64d。
比如HDU(acm.hdu.edu.cn)和CF(codeforces.com)就是典型的Windows下搭建的OJ,不过大部分OJ还是Linux环境运行的。
在提交用到64位整型的代码时一定要注意平台的操作系统,一般可以通过查看OJ的FAQ或在比赛现场咨询裁判获知。
什么是代码能力?简单地说,如果你觉得学会了某一个算法或者数据结构,你能否在半个小时(或一小时)内完成程序,并且经过很少的调试一次通过?如果做不到 的话,只能说你还没彻底掌握这个算法或数据结构,要不断地训练,直到达到要求,只有这样才能保证在高度紧张的比赛中敢于实现而不犯错误。
8. 算法复杂度
复杂度分为时间复杂度和空间复杂度。通俗一点说,就是『跑多快』和『占多大内存』。
在分析复杂度时,我们通常考虑它与什么成正比,并称之为算法的阶。比如程序执行了一个三重循环,每重循环执行n次,那么运行时间就和n4成正比。我们将与n4成正比写作O(n4)。再比如程序开辟了一个二维数组,下标范围是[0..n-1][0..n-1],那么程序的空间复杂度就是O(n2)。
程序的运行时间不仅取决于时间复杂度,也会受计算复杂度、递归等因素的影响,但因此造成的差距最多也就是几倍。
估算一个复杂度是否能承受目前的数据规模时,就将数值可能的最大值待遇复杂度的渐进式中,就能简单的判断算法是否能够满足运行时间限制的要求。比如O(n2)的算法,将n=1000代入得到1000000。通常来讲按照上述方法计算得到108基本是1s时限的最大值。
9. 分治算法
分治,即“分而治之”,就是把一个复杂的问题分成两个或更多的相同或相似的子问题,直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并。总结起来就是:分解、解决、合并,这三大步。
分治策略最经典的一个例子就是折半搜索算法,也就是二分查找——通过不断缩小解可能存在的范围,从而求得问题最优解的方法。二分查找是在有序数组中查找某一特定元素的搜索算法。搜索过程中从数组的中间元素开始,判断待查元素和中间元素的关系,来判断接下来是选择哪一半继续搜索。
由于折半搜索算法每次都把搜索区域减少一半,所以时间复杂度是O(logN),要比朴素算法的O(N)高效许多,这也就是分治策略的优势所在:高效。
分治策略的其他经典例子还有排序算法中的归并排序。归并排序的思路是将待排序的元素分成大致相同的两个子集合,分别对两个子集合进行排序,最终将排序的子集合合并成排好序的集合。
分治所能解决的问题一般具有以下特征:
另外如果每个子问题之间不是独立的,那么就要重复地求解公共的子问题,此时更适合用我们后面会讲到的动态规划算法。
10. 穷举算法 \ 搜索算法
穷举法,又称枚举法,是指从可能的解的集合中一一枚举各个元素,用给定的检验条件判定哪些是无用的,哪些是有用的。能使命题成立即为其解。
穷举法本质上属于搜索算法,但它与搜索有所不同,因为适用于枚举法求解的问题必须满足:可预先确定解的数量;预先确定解变量的取值范围。
穷举算法的关键,首先是确定循环的范围,其次是找出判断解的条件。将这两个关键点解决,穷举算法解题是轻而易举的。
搜索算法和穷举法类似,对于那些无法用循环写出的穷举算法,使用递归或队列来实现求解。搜索的过程构成了一颗搜索树,搜索实际上是对搜索树的遍历。
搜索的顺序分为两种:深度优先搜索(DFS)和广度优先搜索(BFS)。其中深度优先搜索是沿着搜索树的深度遍历树的节点,尽可能深地搜索树的分枝。DFS通常用递归的方法实现。
广度优先搜索每次搜索其可以扩展的每一个节点,当一层节点全部搜索完成后,再依次搜索第一个可扩展节点可以扩展的所有节点。
除了搜索的顺序之外,还有搜索的方法,一般分为盲目搜索和启发式搜索。
启发式搜索是在搜索过程中加入了与问题有关的启发式信息,用于指导搜索朝着最有希望的方向前进,扫除不必要的搜索过程,加速问题求解并得到最优解。
启发式搜索的常见算法有A*算法,模拟退火算法、遗传算法等,我们最常用的是A*算法。A*算法最经典案例是八数码问题,状态函数h设置为未到达目标位置的数字的个数。
11. 内存分区
计算机中的内存在用于编程时,被人为的进行了分区(Segment),分为:
-“栈区”(Stack)
-“堆区”(Heap)
-全局区(静态 区,Static)
-文字常量区和程序代码区
在前面的课程中,我们主要直接涉及到的是栈区的内存,在你的程序中,函数的参数值,局部变量的值等都被存在 了“栈区”,这部分的内存,是由系统来帮助你来管理的,没有特殊情况的时候,你是不需要对其进行特别处理的。计算机中内存的分配如下图。
而针对堆区的内存,一般由程序员进行分配和释放, 使用堆内存的原因一般是
-“栈上内存比较小,不够用”
-“系统管理内存的方式死板,不方便用”
对于堆上的内存,被程序员手动分配后,若程序员 不释放就可能会出现“内存泄漏”。很多企业级的应用,都因为内存泄漏而在“正常”运转很长时间后,轰然“坍塌”。在后面的入门课程中,我们会简单的对这块 的知识进行介绍。
全局区、文字常量区和程序代码区在我们入门阶段,暂时还可以不去过多理解(甚至看不懂也无妨),只需要知道他们的大致作用即可——全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 程序结束后由系统释放;文字常量区是用于储存常量字符串的, 程序结束后由系统释放;程序代码区用于存放函数体的二进制代码。
12. 动态内存分配
i, 申请单个对象
int *p;
p = new int;
ii, 或者你还希望直接在申请的堆内存里直接包含值,比方说一个整数100,你可以写成
int *p;
p = new int();
iii, 动态申请数组
int *p;
p = new int[n];
这样对于一个已经申明的变量n可以申请长度为n的动态数组,就和前面课程学习过的一样;但是这里不能进行初始化。
在这里,请注意一下new后类型后,一个值在圆括号和方括号里的区别。圆括号里值是用来赋初值的,方括号里是用来说明申请堆空间的大小的。
参考文献 “计蒜客” http://www.jisuanke.com/course