写在前面

  • 这个文档是我自己整理的,所以可能会有一些不妥和错误的地方,欢迎大家指正。
  • 因代码风格因人而异,这些代码只是作为一个参考,具体根据自己的习惯和喜好来编写即可。
  • 要深刻理解每句代码的含义,这样才能在需要时能够灵活运用。不要死记硬背!

规范建议

  • 初始化:在定义变量时,明确该变量的作用,从而确定是否需要赋初值。(如当变量需用于求和、计数时需要赋初值为0)
  • 数组定义:不要使用变量(尤其是未经初始化的变量)定义数组长度,直接将数组长度开到最大数据范围加一个常数即可。
  • 代码缩进:在编写代码时注意缩进,这样代码可读性高,后期调试和修改也方便(dev-c++万不得已时可使用Astyle格式化文件)
  • 对于指针:需要掌握,但是否使用取决于个人习惯,如果实在用不来可以使用其它方式代替(比如全局变量,数组传参等)
  • 浮点计算:为了尽量避免精度误差,浮点数计算尽量用double(同时输入时改用%lf,输出时仍用%f)

做题技巧:

  • 平时多做题,锻炼自己的思维、编程能力和解题速度

  • 先构思好算法思路,再开始编写代码

  • 利用辅助变量(可以通过某个变量的几种不同的值来表示不同的情况)

  • 字符可以直接使用ASCII码参与比较和计算(几个常用字符的ASCII码:’0’-48 ‘a’-97 ‘A’-65)

  • 寻找代码操作重复部分加以合并,从而简化代码,节省时间的同时降低后续调试难度

​ 例:车牌限行

1
#include<stdio.h>
2
int main(){
3
	int i,j,k,m,n,d,w,cp;
4
	scanf("%d%d%d",&d,&w,&cp);
5
	cp%=10;
6
	printf("%d ",cp);
7
	if(d>=6) printf("no");
8
	else{
9
		if(w<200) printf("no");
10
		else if(w<400){
11
			if(cp==d||cp==((d+5)%10)) printf("yes");
12
			else printf("no");
13
		}
14
		else{
15
			if(d%2==cp%2) printf("yes");
16
			else printf("no");
17
		}
18
	}
19
	return 0;
20
}
  • 注意查看数据范围,考虑极端数据情况

  • 输入输出(要求,格式,善于观察样例),根据需要选用输入输出方式。

  • 调试(造数据、利用调试工具或者过程变量输出)

  • 写题过程中注意备份任何可能有价值的代码

  • 合理规划时间,把题目都简单看一遍(难度不一定单调递增)

  • 如果题目难实在做不出来可以尝试骗分拿部分分

实用程序片段

将一个数的每位数字取出存入数组

1
//将x每位数字取出存入a数组中
2
int a[20],len=0;//用于存储数字各位的数组
3
while(x){//while(x!=0)
4
    a[++len]=x%10;//取出此时的个位,等价于 len+=1;a[len]=x%10;
5
    x/=10;//x向左移动一位,即去掉个位
6
}
7
if(x==0) a[++len]=0;//特判0

处理结束后,数组$a$从下标为1开始正序存储的即为x从低位到高位的值,$len$ 为数字$x$的位数。

n进制转十进制($2\le n \le 16$)

写法一(倒序循环):
1
//将n进制数s[](用字符数组存储)转换为十进制数x
2
int x=0,w=1;//w为权值
3
for(int i=strlen(s)-1;i>=0;i--){//倒序循环,从最低位开始
4
    int u;//存储该位的值
5
    if(s[i]>='0'&&s[i]<='9') u=s[i]-'0';//如果该位为字符‘0’~‘9’,也可用函数来判断
6
    else if(s[i]>='a'&&s[i]<='f') u=s[i]-'a'+10;//u=s[i]-87;
7
    else if(s[i]>='A'&&s[i]<='F') u=s[i]-'A'+10;//u=s[i]-55; 因不确定字母大小写,所以这里全部写出,可以根据题目实际要求来选择
8
    x+=u*w;//将该位值*权重加到x中
9
    w*=n;//下一位权值为此时权值*进制数n
10
}

如果$n\le10$则可省略判断字母部分,若$n$进制数为int类型则将取字符的步骤改为取模,具体可以参照上一个代码。

(可能更加方便的)写法二(正序循环):
1
int x=0;
2
for(int i=0;i<strlen(s);i++){
3
    int u;
4
    if(s[i]>='0'&&s[i]<='9') u=s[i]-'0';
5
    else if(s[i]>='a'&&s[i]<='f') u=s[i]-'a'+10;
6
    else if(s[i]>='A'&&s[i]<='F') u=s[i]-'A'+10;
7
    //上述代码不变
8
    x=x*n+u;//核心语句,可以自己模拟一下
9
}

特别的,当$n=10$时,题目就变成将一个字符串转换为数字,上述代码则变为:

1
int x=0;
2
for(int i=0;i<strlen(s);i++){
3
    x=x*n+s[i]-'0';
4
}

由于方法二循环是正序的,所以可以用于依次提取字符串中的多个数字串。(P73字符串压缩;P77表达式求值)

十进制转n进制($2\le n \le 16$)

1
//将十进制数x转化为n进制数s[](用字符数组存储)
2
char s[30];int len=0;
3
while(x){//while(x!=0)
4
    char c;
5
    int u=x%n;
6
    if(u>=10) c='a'+u-10;
7
    else c='0'+u;
8
    s[++len]=c;//len+=1;s[len]=c;
9
    x/=n;
10
}
11
if(len==0) s[++len]='0';//特判x为0的情况

注意:此时得到的s在下标$[1,len]$上依次存储的为x转化为n进制时从低位到高位的值,需利用循环倒序输出或处理。

排序

冒泡排序
1
//用冒泡法将a数组1~n的元素从小到大进行排序(升序)
2
for(int i=1;i<n;i++){
3
    for(j=1;j<n-i+1;j++){
4
        if(a[j]>a[j+1]){//改为a[j]<a[j+1]则为降序
5
            int tmp=a[j];
6
            a[j]=a[j+1];
7
            a[j+1]=tmp;
8
        }
9
    }
10
}
11
//若数组下标为0~n-1
12
for(int i=0;i<n-1;i++){
13
    for(j=1;j<n-i-1;j++){
14
        if(a[j]>a[j+1]){//改为a[j]<a[j+1]则为降序
15
            int tmp=a[j];
16
            a[j]=a[j+1];
17
            a[j+1]=tmp;
18
        }
19
    }
20
}
选择排序
1
//用选择法将a数组1~n的元素从小到大进行排序(升序)
2
for(int i=1;i<n;i++){
3
    int k=i;
4
    for(j=i+1;j<=n;j++){
5
        if(a[k]>a[j]) k=j;//改为a[k]<a[j]则为降序
6
    }
7
    if(i!=k){//交换,可以不加这个if判断
8
        int tmp=a[i];
9
        a[i]=a[k];
10
        a[k]=tmp;
11
    }
12
}

求最大公约数(辗转相除法/欧几里得算法)

1
//求a与b的最大公约数
2
int gcd(int a,int b){
3
    if(b==0) return a;
4
    else return gcd(b,a%b);
5
}
6
//简洁的写法
7
int gcd(int a,int b){
8
    return b==0?a:gcd(b,a%b);
9
}

素数判断

1
//判断x是不是素数,是则返回1,不是则返回0
2
int isprime(int x){
3
    if(x<2) return 0;//最小的素数是2
4
    for(int i=2;i<=sqrt(x);i++){
5
        if(x%i==0) return 0;//如果x有因数,则x不是素数,返回0
6
    }
7
    return 1;
8
}