写在前面
- 这个文档是我自己整理的,所以可能会有一些不妥和错误的地方,欢迎大家指正。
- 因代码风格因人而异,这些代码只是作为一个参考,具体根据自己的习惯和喜好来编写即可。
- 要深刻理解每句代码的含义,这样才能在需要时能够灵活运用。不要死记硬背!
规范建议
- 初始化:在定义变量时,明确该变量的作用,从而确定是否需要赋初值。(如当变量需用于求和、计数时需要赋初值为0)
- 数组定义:不要使用变量(尤其是未经初始化的变量)定义数组长度,直接将数组长度开到最大数据范围加一个常数即可。
- 代码缩进:在编写代码时注意缩进,这样代码可读性高,后期调试和修改也方便(dev-c++万不得已时可使用Astyle格式化文件)
- 对于指针:需要掌握,但是否使用取决于个人习惯,如果实在用不来可以使用其它方式代替(比如全局变量,数组传参等)
- 浮点计算:为了尽量避免精度误差,浮点数计算尽量用double(同时输入时改用%lf,输出时仍用%f)
做题技巧:
平时多做题,锻炼自己的思维、编程能力和解题速度
先构思好算法思路,再开始编写代码
利用辅助变量(可以通过某个变量的几种不同的值来表示不同的情况)
字符可以直接使用ASCII码参与比较和计算(几个常用字符的ASCII码:’0’-48 ‘a’-97 ‘A’-65)
寻找代码操作重复部分加以合并,从而简化代码,节省时间的同时降低后续调试难度
例:车牌限行
1 |
|
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 | } |