1. 程式人生 > >ACM 新手入門 之 如何實現多組輸入輸出

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