ACM入门须知

本文作者:弹在枪口
转载请注明
 

目录:

前言
一、输入
二、输出
三、重定向
四、初学者常见问题
五、帮助资料

 

前言:

工欲善其事,必先利其器,在本文之前,先介绍下我们的编码工具(IDE、代码编辑器)

一、输入

第一类:

输入不说明有多少个Input Block,以EOF为结束标志。

参见:HDOJ_1089

http://acm.hdu.edu.cn/showproblem.php?pid=1089

#include <stdio.h>
int main()
{
   int a, b;
   while (scanf("%d %d", &a, &b) != EOF)
       printf("%d\n", a + b);
}
本类输入解决方案:
C语法:
while(scanf("%d %d",&a, &b) != EOF) 
{.... } 
C++语法:
while( cin >> a >> b ) {.... } 
说明:
1.Scanf函数返回值就是读出的变量个数,如:scanf( “%d  %d”, &a, &b ); 如果只有一个整数输入,返回值是1,如果有两个整数输入,返回值是2,如果一个都没有,则返回值是-1。
2.EOF是一个预定义的常量,等于-1。

第二类:

输入一开始就会说有N个Input Block,下面接着是N个Input Block。
参见:HDOJ_1090
#include <stdio.h>
int main()
{
   int n, i, a, b;
   scanf("%d", &n);
   for (i = 0; i < n; i++)
   {
       scanf("%d %d", &a, &b);
       printf("%d\n", a + b);
   }
}
本类输入解决方案:
C语法:
scanf("%d", &n) ;
for ( i = 0 ; i < n ; i++ )
{
   ....
}
C++语法:
cin >> n; 
for ( i = 0 ; i < n ; i++ )
{
   ....
}

第三类:

输入不说明有多少个Input Block,但以某个特殊输入为结束标志。
参见:HDOJ_1091
#include <stdio.h>
int main()
{
   int a, b;
   while (scanf("%d %d", &a, &b) && (a != 0 && b != 0))
       printf("%d\n", a + b);
}
本类输入解决方案:
C语法:
while(scanf("%d",&n)  && n!=0 ) {.... } 
C++语法:
while( cin >> n && n != 0 ) {.... } 

第四类:

以上几种情况的组合 

第五类:

输入是一整行的字符串的 参见:HDOJ_1048  
本类输入解决方案:
C语法:
 char buf[20];  gets(buf); 
C++语法:
如果用string buf;来保存:
getline( cin , buf ); 
如果用char buf[ 255 ]; 来保存: cin.getline( buf, 255 );
说明1 :
scanf(“ %s%s”,str1,str2),在多个字符串之间用一个或多个空格分隔;
若使用gets函数,应为gets(str1); gets(str2); 字符串之间用回车符作分隔。
通常情况下,接受短字符用scanf函数,接受长字符用gets函数。
而getchar函数每次只接受一个字符,经常c=getchar()这样来使用。
说明2 :
cin.getline的用法:
getline 是一个函数,它可以接受用户的输入的字符,直到已达指定个数,或者用户输入了特定的字符。它的函数声明形式(函数原型)如下:
istream& getline(char line[], int size, char endchar = '\n');
不用管它的返回类型,来关心它的三个参数:
char line[]: 就是一个字符数组,用户输入的内容将存入在该数组内。
int size : 最多接受几个字符?用户超过size的输入都将不被接受。
char endchar :当用户输入endchar指定的字符时,自动结束。默认是回车符。
结合后两个参数,getline可以方便地实现: 用户最多输入指定个数的字符,如果超过,则仅指定个数的前面字符有效,如果没有超过,则用户可以通过回车来结束输入。
char name[4];
cin.getline(name,4,'\n');
由于 endchar 默认已经是 '\n',所以后面那行也可以写成:
cin.getline(name,4);
 

二、输出

第一类:

一个Input Block对应一个Output Block,Output Block之间没有空行。
参见:HDOJ_1089
解决方案:
C语法:
{.... printf("%d\n",ans); } 
C++语法:
{ ... cout << ans << endl;} 

第二类:

一个Input Block对应一个Output Block,每个Output Block之后都有空行。
参见:HDOJ_1095
#include <stdio.h>
int main()
{ 
   int a,b;
 while(scanf("%d %d",&a, &b) != EOF)  printf("%d\n\n",a+b);
} 
C语法:
{ ....  printf("%d\n\n",ans); } 
C++语法:
{ ... cout << ans << endl << endl;} 

第三类:

一个Input Block对应一个Output Block,Output Block之间有空行。
参见:HDOJ_1096
#include <stdio.h>
int main()
{
   int icase, n, i, j, a, sum;
   scanf("%d", &icase);
   for (i = 0; i < icase; i++)
   {
       sum = 0;
       scanf("%d", &n);
       for (j = 0; j < n; j++)
       {
           scanf("%d", &a);
           sum += a;
       }
       if (i < icase - 1)
           printf("%d\n\n", sum);
       else
           printf("%d\n", sum);
   }
}
解决办法:
C语法:
for (k = 0; k < count; k++)
{
   while (…)
   {
       printf(" %d\n", result);
   }     
   if (k != count - 1) printf("\n");
}
C++语法:
类似,输出语句换一下即可。
 

三、 重定向

为便于反复测试及再现运行过程,可采用输出、输入重定向的方法。
你只需事先将输入数据存成文件,运行时系统会自动从中获取输入。其效果完全等同于你从(作为默认输入流的)键盘逐项输入。
类似地,你也可以指定另一文件,并使运行的结果自动存入其中。其效果完全等同于从(作为默认输出流的)屏幕截取输出结果。
重定向的好处很多:可以避免手工输入的出错,忠实可靠地重复测试;可以实现大规模数据的输入;可以完整精确地记录程序的输出,以便事后的对比分析;可以省去默认输入、输出流占用的大量时间,更加准确地测量程序的执行效率。
 
a ) 方法一:修改源文件,指定重定向的输入、输出文件 (推荐)
例如,若希望从文件 input.txt 中获取输入,将输出保存到文件 output.txt 中,则可在主程序开头增加如下语句:
#ifndef _OJ_
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
#endif
注意:如果用 c++风格的 cin/cout 的话,还要在前面引用头文件的部分加入
#include <cstdio>
OJ 在编译程序的时候会提供一个 ONLINE_JUDGE 的符号,所以上面这段语句会在 OJ 运行的时候被跳过。
b) 方法二:在 IDE 中通过设置命令行,重定向输入、输出文件
以 Visual Studio 为例,可打开对应工程的“属性页”,在“配置属性”下的“调试”页,设置“命令行参数”。
输入参数不多时,可直接键入。例如 ADD 一题,键入“ 100 200”即可。若其中包含特殊字符,则需以'^'引导,或者使用一对半角括号消除歧义。
若输入参数多,且不止一行,则可将其存成一个文件。比如,可在“命令行参数”中键入:
< D:\test\input.txt
(注意起始字符"<"不能省略)
为将程序的输出保存至指定文件,可在“命令行参数”中继续键入:
> D:\result\output.txt
(同样地,起始字符"<"也不能省略)
若不希望覆盖文件原有的内容,只需用 ">>"替换以上的">",即可将每次运行的输出追加至 D:\result\output.txt。
输入、输出的重定向可同时采用并生效。比如可在“命令行参数”中键入:
< D:\test\input.txt >> D:\result\output.txt
重定向文件的具体路径与文件名可自行选择,但若包含空格,则需使用一对半角引号消除歧义,比如:
< "D:\my test\input.txt" >> "D:\my result\output.txt"
 

四、初学者常见问题

1.编译错误

Main函数必须返回int类型(正式比赛)
不要在for语句中定义类型
__int64不支持,可以用long long代替
使用了汉语的标点符号
itoa不是ansi函数
  能将整数转换为字符串而且与ANSI标准兼容的方法是使用sprintf()函数
int num = 100; 
char str[25];
sprintf(str, " %d" , num);  
另外,拷贝程序容易产生错误

2.C语言处理“混合数据”的问题  

常见的代码:
……
scanf("%d\n", &icase);
for (i = 0; i < icase; i++)
{
   scanf("%c%d%d", &opera, &num1, &num2);
   ……
}
……
上面程序有什么问题?

3.printf和cout混用的问题

以下的程序输出什么?
#include<stdio.h>
#include<iostream.h>
int main()
{
   int j = 0;
   for (j = 0; j < 5; j++)
   {
       cout << "j=";
       printf("%d\n", j);
   }
   return 0;
}
为什么?
一个带缓冲输出(cin/cout)
一个不带缓冲输出(scanf/printf)
cout、cin和printf、scanf最好不要混用。
大数据输入输出时最好不要用cin、cout,防止超时。
详情请参考:《探寻C++最快的读取文件的方案》 http://www.cnblogs.com/Code--Monkey/articles/4131722.html

4.纯字符串用puts()输出:

 数据大时最好用scanf()、printf()减少时间。
 先用scanf(),再用gets()会读入回车。所以在中间加一个getchar();
 不要使用gets(),请使用
char * fgets ( char * str, int num, FILE * stream );
fgets(str, len, stdin);
scanf("%c%c",&c1,&c2)会读入空格;建议用%s读取字符串,取第一个字符。
 单字符输入输出,用getchar/putchar:
char ch;
ch=getchar();

5.一般用C语言节约空间,要用C++库函数或STL时才用C++;

6.有时候int型不够用,可以用long long或__int64(两个下划线__)。

 表示值介于 -2^63 ( -9,223,372,036,854,775,808) 到2^63-1(+9,223,372,036,854,775,807 )之间的整数。
printf("%I64d",a); //__int64 一般VC编译器使用(虽然有的OJ用g++,但是动态链接库用的windows的,所以要用%I64d输入输出)
printf("%lld",a); //long long 一般g++编译器使用

7.OJ判断是只看输出结果的,所以不要要多余的提示输出。

 所以大部分题处理一组数据后可以直接输出,就不需要用数组保存每一个Case的数据。
while(case--)
{
   scanf(...);
   ......
   printf(...);
}

8.读到文件的结尾,程序自动结束:

while( ( scanf(“%d”, &a) ) != -1 )
while( ( scanf(“%d”, &a) ) != EOF)
while( ( scanf(“%d”, &a) ) == 1 )
while( ~( scanf(“%d”, &a) )  )

 读到一个0时,程序结束:

while( scanf(“%d”, &a) , a)
while( scanf(“%d”, &a)!=EOF && a)
 读到多个0时,程序结束:
while( scanf(“%d%d%d”, &a, &b, &c), a+b+c ) //a,b,c非负
while( scanf(“%d%d%d”, &a, &b, &c), a|b|c )

9.数组定义int a[10] = {0};可以对其全部元素赋值为0;

 数组太大不要这样,防止CE。
 全局变量,静态变量自动初始化为0;
 函数中定义的变量存储在栈空间中,数组太大需要定义为全局变量(存储在堆空间中)。

10.有很多数学题是有规律的,直接推公式或用递归、循环。

11.圆周率=cos(-1.0) 自然对数=exp(1.0)

12.如果要乘或除2^n,用位移运算速度快。a>>n;a<<n;

13.定义数组时,数组大小最好比告诉的最大范围大一点。

  字符数组大小必须比字符串最大长度大1。
  处理字符数组时不要忘了在最后加'\0'或者0。

14.擅用三目运算符

int max(int a,int b)
{
   return a>b?a:b;
}
int gcd(int m,int n)
{
   return n?gcd(n,m%n):m;
}
int abs(int a)
{
   return a<0?-a:a;
}

15.将乘法转换成加法减少时间

  log(a*b)=log(a)+log(b)
  将乘法转换成除法防止溢出
  a/(b*c)=a/b/c

16.排序要求不高时可以用C++的STL模板函数sort(),stable_sort()

int a[n]={...};
sort(a,a+n);
bool cmp(int m,int n)
{
   return m>n;
}
sort(a,a+n,cmp);

17.有的题数据范围小但是计算量大可以用打表法

  先把结果算出来保存在数组里,要用时直接取出来。

18.浮点数比较时最好控制精度

#define eps 1e-6
fabs(a-b)<eps

19.有些字符串与整型的转换函数是非标准的

  可以使用sscanf()和sprintf()代替
sscanf(s,"%d",&n);//从字符串s中读入整数n
sprintf(s,"%d",n);//将n转换为字符串s
 

五、帮助资料

1.程序提交后的提示

1) Accepted (AC) :程序已经通过
2) Wrong Answer (WA) : 运行结果不正确
3) Presentation Error (PE) :程序运行结果正确,但结果的格式不正确。
4) Runtime Error (RE) : 程序运行时出错。例如:用0作除数、数据溢出、下标越界。
5) Time Limit Exceeded (TLE) : 超时间限制。
6) Memory Limit Exceeded (MLE) : 超内存限制
7) Compilation Error (CE) : 编译错误

2.在线系统网址:

1) 北京大学: http://poj.org/ 题目丰富全面,但主要是英文题。
2) 百炼: http://poj.grids.cn/ 北京大学内部练习系统。“程序设计导引及在线实践”书本上的例题来自该系统。
3) 浙江大学: http://acm.zju.edu.cn/ “ACM 程序设计”等3本书上的例题来自该系统。
4) 杭州电子科技大学: http://acm.hdu.edu.cn/ 题目相对容易,有中文题、电子教案与代码。
5) 湖南大学: http://acm.hnu.cn:8080/online/ 题目较难。
6) 浙江工业大学: http://acm.zjut.edu.cn/ 题目相对容易,有中文题。
7) 南京航空航天大学:http://acm.nuaa.edu.cn/ 有中文题。
8) 湖南师范大学:http://acm.hunnu.edu.cn/ 有中文基础题。
9) 湖南工业大学:http://openoj.awaysoft.com/ 有中文题。
10) 南阳理工学院: http://acm.nyist.net/ 有很多中文题。
11) 浙江台州学院:http://acm.tzc.edu.cn/ 有很多中文题

3.关于输入输出的进一步问题,可以自己查阅相关手册或资料。 也可参考标准手册,以上输入输出方法都是 C/C++标准输入输出,在 manual 中都有详细介绍。

cin: http://www.cplusplus.com/reference/iostream/cin/

scanf: http://linux.die.net/man/3/printf

对比:http://www.cnblogs.com/Code--Monkey/articles/4131722.html

本文部分内容转载于:power721 http://blog.csdn.net/power721/article/details/4503056
 
 

转载于:https://www.cnblogs.com/swanGooseMan/p/4132132.html

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值