ACM 新手入门 之 如何实现多组输入输出
一般ACM赛制题目都要求 多组输入输出 ,我们以 杭电1000题为例:
题目是很简单的 A+B :代码为:
#include<stdio.h>
int main()
{
int a,b;
scanf("%d%d",&a,&b);
printf("%d\n",a+b);
return 0;
}
但是要求的是多组输入输出,所以上面的代码就不对,得加上这个:
#include<stdio.h>
int main()
{
int a,b;
while (scanf("%d%d",&a,&b) != EOF)// 一律用这种写法,把你的scanf函数写成这样子,除了return 0之外,其他的语句都要用大括号括起来
{
printf("%d\n",a+b);
}
return 0;
}
这样就是简单实现多组输入输出了。对于其他的各种输入输出类型,下面再来介绍:
ACM题目特点: 由于ACM竞赛题目的输入数据和输出数据一般有多组(不定),并且格式多种多样,所以,如何处理题目的输入输出是对大家的一项最基本的要求。这也是困扰初学者的一大问题。 ACM的输入输出要求严格按照规定来,所以你不需要输出像"Please input the data"这类的提示语。否则将会被判Wrong Answer。
1、输入
初学者一般有个误区:如果题目包含多组测试数据,他们就会把输入的内容全部保存起来,然后再依次处理。
其实程序的输入\输出是相互独立的,因此,每当处理完一组测试数据,就应当按题目要求进行相应的输出操作。而不必将所有结果储存起来一起输出。
下面来介绍一下ACM中常见的一些输入情况。
只有一组测试数据
这类题目是最简单的,比如第1000题。(http://acm.hdu.edu.cn/showproblem.php?pid=1000)参考代码:
#include
int main(void)
{
int a, b;
scanf("%d %d", &a, &b);
printf("%d\n", a + b);
return 0;
}
没有明确指出输入什么时候结束
如果是这种情况,我们默认是以“文件结束”(EOF)为结束标志。
这是ACM的默规,例如1076(http://acm.hdu.edu.cn/showproblem.php?pid=1076)题。参考代码:
#include
int main(void)
{
int a, b;
while (scanf("%d %d", &a, &b) != EOF)
printf("%d\n", a + b);
return 0;
}
指定数据量
有时会在数据的第一行提供数据量大小,比如第一行是100,则表示有100组数据。比如第1077题。()参考代码:
#include
int main(void)
{
int n, a, b;
scanf("%d", &n);
while (n--)
{
scanf("%d %d", &a, &b);
printf("%d\n", a + b);
}
return 0;
}
以特定元素作结束符
这种输入和第一种类似。常见的是规定以0作为结束符。
比如第1078题。参考代码:
#include
int main(void)
{
int a, b;
while (scanf("%d %d", &a, &b), a || b)
printf("%d\n", a + b);
return 0;
}
输出
输出格式统一
这种比较简单,只要按要求来就没问题的。比如每组输出占一行,或者每组输出后面加一个空行。比如1000题。
数据之间有空行
(1)对于这种输出,有时候还会告诉你有几组输入,这样你就可以自己判断一下是不是最后一组。是就不输出空行,否则多输出一个空行。而有时候连共有几组数据都不会告诉你。其实不论知不知道有几组数据,我们都可以这样处理。
(2)第一组数据后面不加空行。 第二组开始,每组前面加空行。 比如第1079题,参考代码:
#include
int main(void)
{
int a, b, i = 0;
while (scanf("%d %d", &a, &b), a || b)
printf((i++? "\n%d\n": "%d\n"), a + b);
return 0;
}
下面介绍常用的处理输入的方法
几种常用的处理输入方法(C语言)
感觉新人对于处理输入输出存在一些问题,这里写出几个常用到的处理方法:
1.知道输入数据组数n
scanf("%d",&n);
whlie(n--){
这里处理每一组输入.然后直接按格式输出,没必要开数组存储答案.
}
2.没有数据总数,以EOF结束
可能用的几个函数:
scanf():
while(scanf("%s|%d")!=EOF){
处理每一组数据,并输出.
}
getchar():读入一个字符
whlie((ch=getchar())!=EOF){
}
gets():读入一行
while(gets(buf)!=NULL) {
}
用getchar,gets注意读入换行符.
3.以0或-1结束的输入.
while(scanf("%d",&n),n!=0) {
}
C++ 及 JAVA 的多组输入输出:
关于C++的输入输出处理:
cin读字符串时遇到空白符(空格,换行等)结束
char str[BUFFER];
while (cin >> str) {
}
getline读字符串时遇到换行符结束,用于读一整行
char str[BUFFER];
while (cin.getline(str, BUFFER)) {
}
string str;
while (getline(cin, str)) {
}
cin/cout要比scanf/printf慢一些,尽可能使用scanf/printf以避免测试大量数据时因为输入输出慢而导致TLE. putchar/getchar要比scanf/printf更快
关于java的输入输出处理:
如果使用BufferedReader(jdk1.1或以后的版本,一次读一整行字符串,类似于gets)
BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
String s;
while ((s = stdin.readLine()) != null) {
可以用StringTokenizer st = new StringTokenizer(s);来按空格切词
int n = Integer.parseInt(st.nextToken());
double b = Double.parseDouble(st.nextToken());
}
如果使用Scanner(仅限于jdk1.5或以后的版本,一般用于从字符串中切词,类似于cin)
Scanner stdin = new Scanner(System.in);
while (stdin.hasNext()) {
String s = stdin.next();
int n = stdin.nextInt();
double b = stdin.nextDouble();
}
至于输出,很多新手总会选择先将答案存储在一个数组里,等程序运行完再输出,其实这是没有必要的,机器判决是逐个字符匹配,所以完全可以处理一组输入后,便输出结果。
JAVA 心得 :
ACM采用Java语言心得
Java的优缺点各种书上都有,这里只说说用Java做ACM-ICPC的特点:
(1) 最明显的好处是,学会Java,可以参加Java Challenge 。
(2) 对于熟悉C/C++的程序员来说,Java 并不难学,找本书,一两周业余时间就可以搞定了。当然,这里只是指一般编程,想熟悉所有的Java库还是需要些时间的。事实上,Java 只相当于C++的一个改进版,所有的语法都几乎是C++的,很少有变动。
(3) 在一般比赛中,Java程序会有额外的时间和空间,而实际上经过实验,在执行计算密集任务的时候Java并不比C/C++慢多少,只是IO操作较慢而已。
(4) Java 简单而功能强大,有些东西用Java实现起来更为方便,比如高精度。
(5) 用Java不易犯细微的错误,比如C/C++中的指针, “if (n = m) ... ” 等。
(6) 目前来看Eclipse已成基本配置,写Java程序反而比C/C++更方便调试。在具体竞赛时也算多一种选择。
(7) 学会Java对以后工作有好处。现在国外很多地方会Java的人比会C/C++的人多。
(8) 会Java可以使你看起来更像偶蹄类动物(牛)。
下面说一下ACM-ICPC队员初用Java编程所遇到的一些问题:
1、基本输入输出:
(1) JDK 1.5.0 新增的Scanner类为输入提供了良好的基础,简直就是为ACM-ICPC而设的。
一般用法为:
import java.io.*
import java.util.*
public class Main
{
public static void main(String args[])
{
Scanner cin = new Scanner(new BufferedInputStream(System.in));
...
}
}
当然也可以直接 Scanner cin = new Scanner(System.in);
只是加Buffer可能会快一些
(2)
读一个整数:int n = cin.nextInt(); 相当于 scanf("%d", &n); 或 cin >> n;
读一个字符串:String s = cin.next(); 相当于 scanf("%s", s); 或 cin >> s;
读一个浮点数:double t = cin.nextDouble(); 相当于 scanf("%lf", &t); 或 cin >> t;
读一整行: String s = cin.nextLine(); 相当于 gets(s); 或 cin.getline(...);
判断是否有下一个输入可以用 cin.hasNext() 或 cin.hasNextInt() 或 cin.hasNextDouble() 等,具体见 TOJ 1001 例程。
(3)
输出一般可以直接用 System.out.print() 和 System.out.println(),前者不输出换行,而后者输出。
比如:
System.out.println(n); // n 为 int 型
同一行输出多个整数可以用
System.out.println(new Integer(n).toString() + " " + new Integer(m).toString());
也可重新定义:
static PrintWriter cout = new PrintWriter(new BufferedOutputStream(System.out));
cout.println(n);
(4)
对于输出浮点数保留几位小数的问题,可以使用DecimalFormat类,
import java.text.*;
DecimalFormat f = new DecimalFormat("#.00#");
DecimalFormat g = new DecimalFormat("0.000");
double a = 123.45678, b = 0.12;
System.out.println(f.format(a));
System.out.println(f.format(b));
System.out.println(g.format(b));
这里0指一位数字,#指除0以外的数字。
2、大数字
BigInteger 和 BigDecimal 是在java.math包中已有的类,前者表示整数,后者表示浮点数
用法:
不能直接用符号如+、-来使用大数字,例如:
(import java.math.*) // 需要引入 java.math 包
BigInteger a = BigInteger.valueOf(100);
BigInteger b = BigInteger.valueOf(50);
BigInteger c = a.add(b) // c = a + b;
主要有以下方法可以使用:
BigInteger add(BigInteger other)
BigInteger subtract(BigInteger other)
BigInteger multiply(BigInteger other)
BigInteger divide(BigInteger other)
BigInteger mod(BigInteger other)
int compareTo(BigInteger other)
static BigInteger valueOf(long x)
输出大数字时直接使用 System.out.println(a) 即可。
3、字符串
String 类用来存储字符串,可以用charAt方法来取出其中某一字节,计数从0开始:
String a = "Hello"; // a.charAt(1) = 'e'
用substring方法可得到子串,如上例
System.out.println(a.substring(0, 4)) // output "Hell"
注意第2个参数位置上的字符不包括进来。这样做使得 s.substring(a, b) 总是有 b-a个字符。
字符串连接可以直接用 + 号,如
String a = "Hello";
String b = "world";
System.out.println(a + ", " + b + "!"); // output "Hello, world!"
如想直接将字符串中的某字节改变,可以使用另外的StringBuffer类。
4、调用递归(或其他动态方法)
在主类中 main 方法必须是 public static void 的,在 main 中调用非static类时会有警告信息,
可以先建立对象,然后通过对象调用方法:
public class Main
{
...
void dfs(int a)
{
if (...) return;
...
dfs(a+1);
}
public static void main(String args[])
{
...
Main e = new Main();
e.dfs(0);
...
}
}
5、其他注意的事项
(1) Java 是面向对象的语言,思考方法需要变换一下,里面的函数统称为方法,不要搞错。
(2) Java 里的数组有些变动,多维数组的内部其实都是指针,所以Java不支持fill多维数组。
数组定义后必须初始化,如 int[] a = new int[100];
(3) 布尔类型为 boolean,只有true和false二值,在 if (...) / while (...) 等语句的条件中必须为boolean类型。
在C/C++中的 if (n % 2) ... 在Java中无法编译通过。
(4) 下面在java.util包里Arrays类的几个方法可替代C/C++里的memset、qsort/sort 和 bsearch:
Arrays.fill()
Arrays.sort()
Arrays.binarySearch()
Q:系统返回信息都是什么意思?
A:详见下述:
Pending : 系统忙,你的答案在排队等待.
Pending Rejudge: 因为数据更新或其他原因,系统将重新判你的答案.
Compiling : 正在编译.
Running & Judging: 正在运行和判断.
Accepted : 程序通过!
Presentation Error : 答案基本正确,但是格式不对。
Wrong Answer : 答案不对,仅仅通过样例数据的测试并不一定是正确答案,一定还有你没想到的地方.
Time Limit Exceeded : 运行超出时间限制,检查下是否有死循环,或者应该有更快的计算方法。
Memory Limit Exceeded : 超出内存限制,数据可能需要压缩,检查内存是否有泄露。
Output Limit Exceeded: 输出超过限制,你的输出比正确答案长了两倍.
Runtime Error : 运行时错误,非法的内存访问,数组越界,指针漂移,调用禁用的系统函数。请点击后获得详细输出。
Compile Error : 编译错误,请点击后获得编译器的详细输出。
不用谢,请叫我雷锋!QWQ