ACM系列:入门
——————————————————————————
每次开始新的博客系列之前,都会来一堆废话。作为一个计算机专业的人来说,不会算法总是感觉自己是真的垃圾。也有学长的衷心劝告,作为一名程序猿,在本科阶段还是要抽出至少一年的时间去搞搞ACM,还有我舍友的意见,计算机专业的人不会算法在研究生或者找工作都会被虐的很惨,细思恐惧,可惜我已经浪费了太多的时间,已是大三的老人,也许现在开始还不晚。。。
大概是分为三个部分去整理自己的学习笔记,第一个是C语言的东西,第二个是基础操作,偏向数据结构,第三个就是竞赛题目的操作了。第一步C语言可能就是要去掉脑子里所装的C语言中最没用的那些部分,去掉考试最爱考的那些,emmmm,剩下那些在实际开发中还能有所作用的东西,此中有真意~。嗯,开始吧。
程序设计初始
基础操作
虽然已经学过了C语言,还用C语言写过点东西,但还是从头开始吧,从最基础的int a开始。
#include <stdio.h>
int main()
{
printf("%d\n", 1 + 2);
printf("%d\n", 8 / 5); //整数与整数的运算的结果是整数
printf("%.1f\n", 8.0 / 5); //浮点数与浮点数运算的结果是浮点数
return 0;
}
输出的结果如下:
3
1
1.6
变量及其输入
以计算一个圆柱的面积为例,输入底面半径
,高
,计算表面积
。
样例输入:3.5 9
样例输出:Area = 274.889
#include <stdio.h>
#include <math.h>
int main()
{
float a, b;
float s1, s2;
const float PI = acos(-1.0);
scanf("%f%f", &a, &b);
s1 = PI * a * a * 2;
s2 = 2 * PI * a * b;
printf("Area = %.3f", s1 + s2);
return 0;
}
程序的运行结果:
3.5 9
Area = 274.889
注意事项:不要在用户输入之间加入乱七八糟的东西,比如”Please input radius and height”,这样不会赢得界面友好分,还比标准答案多了一行,多此一举还不讨好。还有多余的getchar()也不要加,每行以回车作为结束符,每行的开始不能有空格,每行的结尾可以有任意的空格,输出的两个数字或者字符数组以单个空格隔开。读入数据,打印结果,程序退出即可,没必要用getchar去暂停程序观看结果。
做几个例子熟悉这种风格。
样例输入:250。样例输出:052。
#include <stdio.h>
#include <math.h>
int main()
{
int n, m;
scanf("%d", &n);
m = (n % 10) * 100 + (n /10 % 10) * 10 + n / 100;
printf("%03d\n", m); //输出三位,高位补0
return 0;
}
样例输入:14,15。样例输出:15,14。
#include <stdio.h>
#include <math.h>
int main()
{
int n, m;
scanf("%d,%d", &n, &m);
printf("%d,%d\n", m, n); //没说要交换变量,意不意外
return 0;
}
本小节结束
—————————————————————————————————————————————————————–
循环程序设计
以下的复习内容会以实例为主,穿插着一些细微的知识点,毕竟纸上得来终觉浅。
for 循环
搜寻10000以内形如aabb式的完全平方数。
#include <stdio.h>
#include <math.h>
int main()
{
int n;
float m;
for (int i = 1; i < 10; i++) //先执行i++,在判断i<10是否成立
for (int j = 1; j < 10; j++)
{
n = i * 1100 + j + j * 10;
m = sqrt(n) + 0.5;
m = floor(m);
if (m * m == n)
{
printf("%d\n", n);
}
}
return 0;
}
然而,众所周知,涉及到开平方终究会涉及到浮点的精度问题,判断两个浮点数是否相等,一般会采取(a-b<1e-7)这样的形式,因此采取了floor(向下取整,1.5=1,1.9=1)。但是感觉精度不容易控制呢?那就不如用枚举的暴力形式去求解。
#include <stdio.h>
#include <math.h>
int main()
{
int n, x, a, b, c, d;
for (n = 1; ; n++)
{
x = n * n;
if (x < 1000)
continue; //continue 跳过下面的语句,重新开始循环
if(x > 9999)
break; //break 跳出循环
a = x / 1000;
d = x % 1000 % 100 % 10;
b = (x / 100) % 10 ;
c = (x /10) % 100 % 10;
if (a == b && c == d)
printf("%d\n", x);
}
return 0;
}
while与do-while。
对于大于1的自然数
,若其为奇数,
,若其为偶数,
,最终
一定会变为
,输出其变换次数。
#include <stdio.h>
#include <math.h>
int main()
{
int n, count = 0; //初始化变量
scanf("%d", &n);
while (n > 1) // n>1时执行此循环
{
if (n % 2 == 1)
{
n = 3 * n + 1;
count++;
}
else
{
n = n / 2;
count++;
}
}
printf("%d\n", count);
return 0;
}
然而上面的程序有问题,why?因为当你输出的数太大时,会导致精度溢出,两种方案,一种是换成unsigned int类型,另一种是long long类型,但是long long 类型在linux下的输入输出格式为%lld,Windows平台下有时为%I64d,为了保险起见,可以用C++流,这里不做介绍。
循环的代价
写个循环,看看你的程序执行的多长的时间。计算
共计花费多长时间。
#include <stdio.h>
#include <math.h>
#include <time.h>
int main()
{
int n, sum = 0;
scanf("%d", &n);
for (int i = 1; i <= n; i++)
{
int temp = 1;
for (int j = 1; j <= i; j++)
{
temp = temp * j;
}
sum = sum + temp;
}
printf("%06d\n", sum % 1000000);
printf("time used :%.2fs", (double)clock() / CLOCKS_PER_SEC);
return 0;
}
遗憾的是,输入数据的时间也被记在算法的执行时间内,我们想要核心算法的执行时间,How to deal it?方法总比问题多,在命令行输入:
echo 20|test.c //20作为输入,test.c是程序的文件名
//以下是执行部分
C:\Users\暮雨\Desktop\ACM\second\second\Debug>echo 20 | second.exe
040729
time used :0.00s
算法竞赛的输入输出框架(待续)
* *