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,只有truefalse二值,在 if (...) / while (...) 等语句的条件中必须为boolean类型。

C/C++中的 if (n % 2) ... Java中无法编译通过。

(4) 下面在java.util包里Arrays类的几个方法可替代C/C++里的memsetqsort/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 

posted @ 2018-10-16 19:56  RomanticChopin  阅读(778)  评论(0编辑  收藏  举报
-->
Live2D