前言:本篇总结一部分来自刘汝佳老师的《算法竞赛入门经典》,一部分是个人竞赛学习中的一些算法知识点总结,是初学算法走了不弯路一点点积累起来的干货,对刚刚参加竞赛的盆友应该会很有帮助,如有不足请提出
1.”%.1f” 保留小数点后一位
2.整数/整数=整数,浮点数/浮点数=浮点数
3.sqrt(x)=x的算数平方根
4.在算法竞赛中不要使用头文件conio.h,包括getch()、
clrscr()等函数。
5.在算法竞赛中,每行输出均应以回车符结束,包括最后一行。除非特别说明,每行的行首不应有空格,但行末通常可以有多余空格。另外,输出的每两个数或者字符串之间应以单个空格隔开。
6.三位数反转,反转后结果可以用printf函数控制
320→023:
#include
int main() {
int n, m;
scanf("%d", &n);
m = (n%10)*100 + (n/10%10)*10 + (n/100);
printf("%03d\n", m);
return 0;
}
320→23:
#include
int main() {
int n, m;
scanf("%d", &n);
m = (n%10)*100 + (n/10%10)*10 + (n/100);
printf("%d\n", m);
return 0;
}
7.输出\n:printf("\\\n")
; 输出%d:printf("%%d")
;
8.int整数大小:-2147483648~2147483647
,即-2^31~2^31-1
。
9.long long大小:-2^63~2^63-1
,注意int输入的格式控制符改为%lld
,Windows输入改为%I63d
1.不拘一格地使用伪代码来思考和描述算法是一种值得推荐的做法。
2.x四舍五入:floor(x + 0.5)
; //floor返回不超过x的最大整数
3.浮点运算可能存在误差。在进行浮点数比较时,应考虑到浮点误差。
4.while适用于循环的次数是不确定的,而且n也不是“递增”式的循环。这样的情况
5.计算程序运行时间:printf("Time used = %.2f\n", (double)clock() / CLOCKS_PER_SEC)
;//在程序结束之前调用此函数,便可获得整个程序的运行时间。这个时间除以 常数CLOCKS_PER_SEC
之后得到的值以“秒”为单位。用文件方式读入,要不然会计算键盘输入的时间
可以使用time.h和clock()函数获得程序运行时间。常数
CLOCKS_PER_SEC和操作系统相关,请不要直接使用clock()的返回值,而应总是除以CLOCKS_PER_SEC
。
6.文件读写操作
文件读入:freopen(“文件地址”,“r”,stdin);
写到文件:freopen(“文件地址”,“w”,stdou);
7.在观察无法找出错误时,可以用“输出中间结果”的方法查错
8.当输入数据个数不定时,且没有限制条件:
while(scanf("%d", &x) == 1)
{
执行操作
}
直接用键盘停止输入
在Windows下,输入完毕后先按Enter
键,再按Ctrl+Z
键,最后再按Enter
键,即可结束输入。在Linux下,输入完毕后按Ctrl+D
键即可结束输入。
9.变量在未赋值之前的值是不确定的。特别地,它不一定等于0
10.当变量大于其类型最大值是会产生溢出,运行结果会出现#INFO
解决技巧:如1/i*i 溢出 变化成:1/i/i
11.巧妙用输出来控制精确:a精确到c位:printf(“%.*f”,c,a);
1.在算法竞赛中,常常难以精确计算出需要的数组大小,数组一般会声明得稍 大一些。在空间够用的前提下,浪费一点不会有太大影响。
2.比较大的数组应尽量声明在main函数外,否则程序可能无法运行。
3.数组a赋值k个元素到数组b
#include
memcpy(b,a,sizeof(类型)* k)
给数组每个元素赋相同初值
memset(数组名,初值,sizeof(数组名));//常用于初始化
或者
memset(数组名,初值,sizeof(类型)*大小)
注意:int类型只能赋值0和-1
4.字符串数组char s[m][n] 可以用scanf(“%s”,s[i])读取第i个字符串
5.C语言中的字符串是以“\0”结尾的字符数组,可以用strlen(s)返回字符串s中结束标记之前的字符个数。
6.两个数组操作函数
赋值:strcpy(a,b)//b赋值给a
比较:strcmp(a,b)//a>b返回1
连接:strcat(a,b)//返回里连接后字符串
7.头文件include
isalnum(a) 测试传入参数是否为为字母或数字,真返回值为非零
isalpha(a) 测试传入参数是否为字母,真值返回非零
isdigit(a) 测试传入参数是否为数字,真值返回非零
8.如果char 值为正,则是西文字符;如果为负,则是汉字的前一半(这时需要再读一个char)
9 函数的参数和返回值最好是“一等公民”,如int、char或者double等。其他“非 一等公民”作为参数和返回值要复杂一些。如果函数不需要返回值,则返回类型应写成 void。
10.在C语言中,定义结构体的方法为“struct 结构体名称{ 域定义 };
”,注意花括号的后面还有一个分号。
11.为了使用方便,往往用“typedef struct { 域定义; }类型名
;”的方式定义一个新类型名。这样,就可以像原生数据类型一样使用这个自定义类型。
12.结构体定义
第一种 struct point{
int x ;int y}; 使用: struct point a;
第二种 typedef struct{
int x;int y}point; 使用:point a;
13.对复杂的表达式进行化简有时不仅能减少计算量,还能减少甚至避免中间结果溢出
14.“判断一个事物是否具有某一性质”的函数还有一个学术名称——谓词(predicate)
建议把谓词(用来判断某事物是否具有某种特性的函数)命名成is_xxx
的形式,返回int值,非0表示真,0表示假。
15.在调用函数调用数组时,参数传递是传递数组的首地址,所以不能用sizeof(a)计算数组的大小,正确做法是在传递数组长度参数n
16.While()输入巧用
While(scanf("%d%d%d",&a,&b,&c)==3){
}
//scanf(“%d%d%d”)==3 是判断是否输入完毕和输入的数是否有效
while(scanf("%d%d%d",&a,&b,&c)!=EOF){
}
//EOF表示结束标志
while(getchar()!='\n'){
};
//利用回车来巧妙结束循环
17.全局变量要少用
18.strcmp(a,b)函数
比较字符串a,b大小;相等返回0;a>b返回1;a<b返回-1
19.注意:在参加比赛时,千万不要在使用for循环的时候命名变量,可能会因为编译器兼容的原因是编译不通过,直接零分,最好在函数开始就命名
20.在实际问题中,如果利用输出函数来规定输出的小数位数,很可能会因为四舍五入而得不到正确结果,这是可以用这种方法来解决四舍五入
a=(int)(a*100)/100.0; //防止四舍五入,首先将多余位给切掉,再还原成小数
printf("%.2f\n",a);
//注意a*100一定要加括号
1.头文件
#include → #include< cstdio >
#include → #include< cstring >
#include → include < cmath >
#include → include< ctype >
#include< iostream > 提供了输入输出流
#include< algorithm > 提供常用算法
2.using namespace std
名称空间(写在函数开头)
3.声明数组: #define maxn 50 → const int maxn=50
4.C++中的数据类型和C语言很接近,最显著的区别是多了一个bool来表示布 尔值,然后用true和false分别表示真和假。虽然仍然可以用int来表示真假,但是用bool可以 让程序更清晰
5.void swap2(int& a, int& b)
如果在参数名之前加一个“&”符号,就表示这个参数按照传引用(byreference)的方式传递,而不是C语言里的传值(by value)方式传递。这样,在函数内改变参数的值,也会修改到函数的实参。
6.C++中的引用就是变量的"别名",它可以在一定程度上代替C中的指针。例如,可以用“传引用”的方式让函数内直接修改实参。
1.数学函数 double ceil(double);
功能:返回大于或者等于指定表达式的最小整数
2.scanf()函数输入字符串时,当读到空格就会停止输入
例如
char a[20] sacnf(“%s”,a),输入”I LOVE YOU”最后读入的只有‘I’
scanf(“%[^\n]”,a)除了换行符外其他字符全部接收
3.负数的二进制(表示负数的补码)
"-1"转为二进制的过程
第一步:找原码"1"的8位二进制表示为00000001
第二步:找原码的反码为11111110
第三步:找补码(反码加一):11111111。
4.各输出格式控制代码如下:
int PrintVal = 9;
/*按整型输出,默认右对齐*/
printf("%d\n",PrintVal);
/*按整型输出,补齐4位的宽度,补齐位为空格,默认右对齐*/
printf("%4d\n",PrintVal);
/*按整形输出,补齐4位的宽度,补齐位为0,默认右对齐*/
printf("%04d\n",PrintVal);
/*按16进制输出,默认右对齐*/
printf("%x\n",PrintVal);
/*按16进制输出,补齐4位的宽度,补齐位为空格,默认右对齐*/
printf("%4x\n",PrintVal);
/*按照16进制输出,补齐4位的宽度,补齐位为0,默认右对齐*/
printf("%04x\n",PrintVal);
/*按8进制输出,默认右对齐*/
printf("%o\n",PrintVal);
/*按8进制输出,补齐4位的宽度,补齐位为空格,默认右对齐*/
printf("%4o\n",PrintVal);
/*按照8进制输出,补齐4位的宽度,补齐位为0,默认右对齐*/
printf("%04o\n",PrintVal);
5.等差数列通项,前n项和
通项:an=a1+(n-1)*d;
前n项和:Sn=a1*n+(n(n-1)d)/2;
Sn=n(a1+an)/2;
6.等比数列通项,前n项和
通项: an=a1*q^(n-1);
前n项和: 当q=1时 Tn=n*a1;
当q!=1时 Tn=a1(1-q^n)/(1-q)
7.只有以\0
结束的字符数组才可以以s%
的方式用printf输出,否则输出会 非常奇怪,自己在char数组上构造一个字符串的时候,忘记在末尾加\0
可能会导致访问非法内存的错误
8.字符串拼接函数: char* strcat(char *dest,char *source)
,可以将source字符串拼接到dest后面
9.声明数组全局变量会自动清零,局部变量需要手动清零
10.char a[10]; strlen(a+1)
会从第二个数开始数到数组结尾,不要将strlen(a)写在for循环里面,否则循环一次计算一次会大大减低速度,正确做法是保存到变量中;
11.闰年:
满足一下任意一个条件都是闰年
1.年份非整百且能被4整除的为闰年
2.年份能被四百整除的是闰年(闰年二月29天,平年28天,大月31天,小月30天)
判断是否为闰年代码:
int is_leap_year(int year)
{
if(year%400==0||(year%100!=0&&year%4==0))
return 1;
else
return 0;
}
12.蔡基姆拉尔森公式
13.C语言qsort()排序函数(默认从小到大,从大到小直接对cmp返回值取反)
#include
int cmp(const void*a,const void*b)
{
return (*(int*)a-*(int*)b);
}
qsort(起始地址,排序元素个数,sizeof(类型),cmp);
14.c++排序函数
#include
using namespace std;
sort(a,a+n);
如果要从大到小排序则加一个函数
sort(a,a+n;cmp);
bool cmp(int a,int b)
{
return a>b;}
21.万能头文件:#include
22.round(a)求离a的最近整数
23.常用数学函数(math.h)
(1)fabs(double x) 求绝对值
(2)floor(double x)向下取整 ceil(double x)向上取整
(3)pow(double x,double y)x 的y次方
(4)sqrt(double)返回算术平方根
24.String二维数组string mp[1005]
初始化
for(int i=0;i<n;i++)mp[i].resize(m);//先要个数撑起来
for(int i=0;i<n;i++)mp[i].resize(m,t)//会初始化为t值
25.周期性运动通式
guess(起点,方向,步数){
while(步数--){
终点=(起点+方向+周期-1)%周期+1;
}
26.一颗包含有2019个节点的二叉树,最多包含多少个叶节点
各个节点之间的关系:n=n0+n1+n2,为了使叶子结点(n0)最多,必须n1最小即设为0; 有关系n0=n2+1
得到n2=(2019-1)/2=1009,所以n0=1010;
27.用while输入字符串
while((c=getchar())!=EOF&&c!=’\n’){
a[len++]=c;
}
注意:c=getchar()必须打包处理