2013年10月23日 星期三

線上檢測小記事 - 處理多筆輸入

進行線上檢測,另一個大問題就是多筆輸入了

因為不知道總共會有幾筆資料所以必須透過一些小技巧來進行

以下大約列出幾種常見的測試資料輸入範例

會以 UVa 的題目做為例題,但是因為這篇只討論輸入部份所以不會完整解題

Case 1. 多筆輸入直到檔案結尾

Example: UVa 10494 If We Were a Child Again

Partial code:
int a, b;

char math;


// This is a solution. 

while( scanf( "%d %c %d", &a, &math, &b ) != EOF )

{ /* Some code here. */ }


//This one is also ok.

while( scanf( "%d %c %d", &a, &math, &b ) == 3 )

{ /* Some code here. */ }
每呼叫一次 scanf() 都會產生兩種效果:

第一個效果是會讓使用者的輸入送進指定的變數中,

而第二個效果是在接收完使用者輸入之後,

scanf() 會將自身這串替換成一個數字 (此即 scanf() 的返回值,若不知道函數的返回值是什麼,就想像這整段會變成一個數字好了)

因為這裡 scanf 共接收了三個來自使用者的輸入( a, math, b 共3個變數),所以 scanf() 會變成3

若為 scanf( "%d", &a ); 的話,那麼它將會變成 1,因為它只接收一個變數

以此例來講的話,在輸入完3個變數之後,這句將變成
//上面那種做法 

while( 3 != EOF ) ...... //這個 3 是 scanf 變成的

//下面的做法

while( 3 == 3 ) ......
此時條件成立,故迴圈將繼續進行

當 scanf() 接收到檔案結尾的時候,它會變成 EOF,程式實際上將變成
//上面那種做法 

while( EOF != EOF ) ......

//下面的做法

while( EOF == 3 ) ......
這時候條件不成立,迴圈將結束而跳出

Case 2. 給定資料數,再輸入該數量的資料

Example: UVa 11547 Automatic Answer

Partial code:
int t, i, input; // i 只是一個計數器

scanf( "%d", &t ); // t 代表接下來有幾筆測試資料


// This is a solution.

while( t-- )

{ scanf( "%d", &input ); } //實際上還有許多 code 要打,當然不只這些


// Here's another solution. Please choose only 1 solution for this.

// This solution is longer, but more understandable.

for( i = 0; i < t; ++i )

{ scanf( "%d", &input ); }

Case 3. 多筆資料,以 0 表示輸入結束

Example: UVa 10550 Combination Lock

Partial code:
int a, b, c, d; //一次有四個數字進來,所以弄出 abcd

while( scanf( "%d %d %d %d", &a, &b, &c, &d ) && ( a+b+c+d ) )

{ /* Some code here. */ }

這麼用法是因為 while 迴圈裡出現了 && 運算符,

scanf() 將會變成 4 (見 Case 1 說明), 而非 0 的數在 C 裡面會視為 True 並繼續進行 && 後的條件判斷

又提及,非 0 的數為 True,則若為 0 時就是 False,

當最後一筆四個 0 出現時, a+b+c+d = 0,會視為 False (不成立),

因而跳出 while 迴圈而結束

Case 4. 多筆輸入,以某一特定文字、數字、字元做為結束

Example 1: UVa 12577 Hajj-e-Akbar

Partial code:
char input[ 20 ];


while( scanf( "%s", input ) && input[ 0 ] != '*' )

{ /* Some code here. */ }

當最後一筆輸入 * 的時候,會使得 && 後面的條件判斷不成立(因為 input[ 0 ] 為 *)

所以會結束迴圈

Example 2: UVa 12468 Zapping

Partial code:
int a, b;


while( scanf( "%d %d", &a, &b ) && ( a != -1 || b != -1 ) )

{ /* Some code here. */ }

這裡題目約定了兩個 -1 代表輸入的結束,

所以將它們寫到 && 的後面進行判斷(注意到我們可以不必用 EOF 來判斷迴圈的結束,所以可以不必寫 != EOF 來節省程式碼長度)

當兩個數字都是 -1 時, && 後的條件都會不成立所以變成 False 而跳離迴圈

又因為 || 的運算優先序比 && 低,所以 || 必須括號起來一起運算

沒有留言:

張貼留言