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