#include <stdio.h>
long long A,L; //避免乘法溢出
int cases=0;
int main(){
while(scanf("%lld %lld",&A,&L)!=EOF&&A>0&&L>0){ //在UVa中,要用lld才行
cases++;
printf("Case %d: A = %lld, limit = %lld, ",cases,A,L);
int count=0;
while(1){
if(A>L){
break;
}
if(A==1){
count++;
break;
}
else if(A%2==0){
A=A/2;
count++;
}else{
A=A*3+1;
count++;
}
}
printf("number of terms = %d\n",count);
}
return 0;
}
2014年8月31日星期日
[UVa] 694 - The Collatz Sequence
2014年8月30日星期六
[UVa] 489 - Hangman Judge
#include <stdio.h> #include <string.h> char c[101]={'\0'},s[101]={'\0'}; int round,fail=0,lose=0; int main(){ while(scanf("%d",&round)!=-1){ if(round==-1)break; printf("Round %d\n",round); scanf("%s",&s); //solution scanf("%s",&c); //string to guess lose=0; for(int i=0;i<100;i++){ fail=1; //set fail = 1 for(int j=0;j<100;j++){ if(c[i]==s[j]){ fail=0; //有檢查到相同的字元,則本次猜測成功,fail設為0 s[j]='\0'; //將被猜到的相同字元都換成'\0' } } if(fail==1)lose++; //沒檢查到相同字元,本次猜測失敗,lose++ char check = c[i]; //將原字串內本次猜測的字都換為'\0',避免重複猜測 for(int j=0;j<100;j++) if(c[j]==check)c[j]='\0'; //如果失敗次數>=7次,輸出You lose. if(lose>=7){ printf("You lose.\n"); break; } else { //這裡很重要,目前失敗還沒七次的話,趕緊檢查是否已經猜到全部的字了 int win=1; for(int i=0;i<100;i++){ if(s[i]!='\0'){ win=0; //如果被檢查的字串裡還有剩餘沒猜到的字,win設為0 break; } } if(win==1){ //如果都檢查到了,win=1,輸出You win. printf("You win.\n"); break; } } } //判斷最後的狀況,有剩字沒檢查且lose次數<7,輸出You chickened out. for(int i=0;i<100;i++){ if(s[i]!='\0'&&lose<7){ printf("You chickened out.\n"); break; } } //重新初始化陣列 for(int i=0;i<100;i++){ c[i]='\0'; s[i]='\0'; } } return 0; }
[UVa] 445 - Marvelous Mazes
#include <stdio.h>
#include <string.h>
int main(){
char input;
int count=0;
while(1){
input = getc(stdin);
if(input==EOF)break;
if(input>=48&&input<=57)count += input-48; //0~9
else if(input=='!'||input=='\n')printf("\n"); //換行
else
while(count>0){ //根據先前累積的總和來決定輸出次數
if(input=='b')printf(" "); //如果是b輸出空白
else printf("%c",input); //輸出原字元
count--;
}
}
}
2014年8月29日星期五
[UVa] 490 - Rotating Sentences
#include <stdio.h> #include <string.h> char c[100][100]; char input; int main(){ //初始化陣列 for(int j=0;j<100;j++) for(int i=0;i<100;i++) c[i][j]='\0'; //i為橫向,j為縱向,從右上角開始 int i=99,j=0; while(1){ input = getc(stdin); if(input==EOF)break; if(input=='\n'){ //遇換行則從前一行的最上面開始 j=0; i--; }else{ c[i][j] = input; j++; //不斷往下寫入 } //if(input)break; } i++; int flag=i; //設定旗標,標在倒數第i行,輸出都從這邊開始往右 int check=0; for(j=0;j<100;j++){ while(i<100){ if(c[i][j]!='\0')printf("%c",c[i][j]); else printf(" "); i++; if(c[i][j+1]!='\0'){check=1;} //順便檢查下一行 } //如果下一行還存有資料,輸出換行,否則就跳出迴圈 if(check==1)printf("\n");else break; check=0; i = flag; //輸出完一列,就要將i跳回旗標開始處 } return 0; }
[UVa] 414 - Machined Surfaces
#include <stdio.h>
#include <string.h>
char c[30]={'\0'};
int s[14];
int main(){
int n,count=0,i,j,max=0;
for(i=0;i<14;i++)s[i]=0; //初始化
n=1;
while(n!=0){
scanf("%d",&n); //輸入row數
if(n==0)break;
getchar(); //避免scanf的enter被讀入
for(i=0;i<n;i++){
count=0;
for(j=0;j<30;j++)c[j]=' ';
fgets(c,sizeof(c),stdin);
for(j=0;j<sizeof(c);j++){
if(c[j]=='X')count++; //每一次讀入一行,就總X數++
}
s[i]=count; //把每一列的X數都存起來
if(count>max)max=count; //取得每一列的X數最大值
}
/*
for(i=0;i<n;i++){printf("%d ",s[i]);}
printf("\n");
*/
int total=0;
for(i=0;i<n;i++){
total+=max-s[i]; //total計算最多X列的X數量和其他每一列的差加總
}
printf("%d\n",total);
max=0;
}
}
2014年8月28日星期四
[UVa] 494 - Kindergarten Counting Game
#include <stdio.h>
#include <string.h>
#include <ctype.h>
char c[1000]={'\0'};
int i;
int main(){
while(fgets(c,sizeof(c),stdin)){
int count=0;
for(i=0;i<=strlen(c);i++){
if(isalpha(c[i]) && !isalpha(c[i+1]))count++;
}
printf("%d\n",count);
}
return 0;
}
2014年8月27日星期三
[UVa] 458 - The Decoder
#include <stdio.h> #include <string.h> char c[1000]={'\0'}; int main(){ while(fgets(c,sizeof(c),stdin)){ for(int i=0;i<strlen(c)-1;i++){ printf("%c",c[i]-7); } printf("\n"); } }
[UVa] 10300 - Ecological Premium
乘上第一個數和第三個數,在加總即可
動物的數量會先被除掉再乘回來
#include <stdio.h>
int n,f;
int main(){
while(scanf("%d",&n)!=EOF){
for(int i=0;i<n;i++){
int count=0;
scanf("%d",&f);
while(f>0){
f--;
int a,b,c;
scanf("%d %d %d",&a,&b,&c);
count += a*c;
}
printf("%d\n",count);
}
}
}
2014年8月26日星期二
[UVa] 264 - Count on Cantor
一開始用數學方法推斷得出,設輸入為n
k為在n的前一斜線列數,故只要找到 (1+k)*k/2 < n 的最大k值,即可判定
k%2 == 1 => ((2*n)-(k*k)-k)/2 / ((k*k)+(3*k)-(2*n)+4)/2
k%2 == 0 => ((k*k)+(3*k)-(2*n)+4)/2 / ((2*n)-(k*k)-k)/2
其實還有更好的方法
令 s 為包含n那一斜列的總項數
偶數列由左下至右上數,故分子為 s-n+1,分母為 k - (s-n)
k % 2 == 1 => s-n+1 / k-s+n
k % 2 == 0 => k-s+n / s-n+1
#include <stdio.h> #include <stdlib.h> int main(){ int k,n; while(scanf("%d",&n)!=EOF){ k=1; for(k=1;(k*k+k)/2<n;k++); k--; //printf("k=%d\n",k); if(k%2==1)printf("TERM %d IS %d/%d\n",n,((2*n)-(k*k)-k)/2,((k*k)+(3*k)-(2*n)+4)/2); if(k%2==0)printf("TERM %d IS %d/%d\n",n,((k*k)+(3*k)-(2*n)+4)/2,((2*n)-(k*k)-k)/2); } return 0; }
2014年8月24日星期日
關於Online Judge的輸入輸出
文章出處:http://infbugs.blogspot.tw/2011/12/c_20.html
謝謝沙耶,解答了我長久以來對於 input/output 的疑惑。
謝謝沙耶,解答了我長久以來對於 input/output 的疑惑。
C 語言入門 - 在線上批改系統練功
如何練習使用基本語法
自己出個練習題試著寫寫看?寫完隨手測幾個數字發現正確無誤就好了嗎?這樣其實比較辛苦,不如我們找找網路上既有的練習題試試,說不定別人想到我們沒想到 的巧妙題目,寫完了只要上傳程式碼還能自動判斷執行效率以及正確與否,多麼方便啊!這種網站去哪找?網路上現在不少,這裡介紹個我比較熟悉,也相當常見的 網站。
UVa Online Judge
台灣俗稱 ACM 的網站。由來是它收錄了不少 ACM ICPC 競賽的題目。詳細介紹留待之後的文章。網址如下:
http://uva.onlinejudge.org
雖然是英文的,不過也有些好心人翻譯了不少題目出來。網址如下:
http://163.32.78.26/
網站本身不太穩定,如果死掉了可以先用別人架的鏡像站。但是鏡像站的資料較古舊,有些比較新的翻譯可能沒更新到。但也已有相當數量的題目翻譯了。如果原網站沒問題,建議還是不要用鏡像站。以下是其中一個鏡像站:
http://w.csie.org/~b97115/luckycat/
但是並非所有題目均有翻譯。翻譯的速度通常是跟不上寫的速度,也與各譯者擅長與不擅長有關,日後仍有必要直接閱讀英文題目。現階段主要是在這裡可以方便找 到許多難度僅有一顆星的題目。未翻譯的題目中也有許多難度僅有一顆星的程度,但是並不好找,對初學者而言更無從著手。就以目前到這篇為止,也不足以解開所 有一顆星程度的題目。文末會列出此時較適合寫的題目。
首先我們連上 UVa 的網站,左上角登入欄的底下有個 Registre 的連結,點它。Username 是你的帳號,而 Name 是你的名字。如果你沒有使用過它的舊網站,也沒印象持有舊網站 ID 的話,在 Online Judge ID 填上 00000,否則填上舊網站 ID 則可以把舊帳號整合過來。Results Email 則可以自行選擇勾或不勾。勾的話你之後有上傳題目,它會把結果寄到你的信箱。沒有勾的話也能在網站上看到結果,所以不影響。如果不嫌它很煩的話建議是勾一 下,好處是它若發現某道題目需要重新判定大家上傳的程式碼正確與否 (通常是測試不夠嚴謹以致於錯誤的程式碼被判成正確) 的話,在收信時會發現。
之後請到信箱收認證信,收到後就完成註冊了。接下來在 UVa 登入後,就可以上傳你的程式碼了。請注意如果勾選 Remember me 再登入的話,以後有可能導致沒辦法連上。如果遇到這種情形,請開啟 Chrome 的無痕瀏覽,或 Firefox 的私密瀏覽試試,或是把瀏覽器的 cookie 清掉。
目前能解的題目,有以下幾題:
10071
10300
11172
100
488
未列出不代表不能解,這裡只是列出可解的幾道題。但是在開始寫之前,有幾個地方需要特別注意。
這篇文章放在這個順位,理應存在相當多目前難以說明的東西,硬要作說明則會出現不少新東西要記,也有許多很難講明白的地方。這裡已經盡量講得淺白易懂,若一時記不完可以先大致看過,等到寫一寫出問題再回來查。
征服 UVa 的行前準備:了解線上批改系統
首先我們必須了解它的基本規則。這類網站人稱 Online Judge,多譯作「線上批改系統」或類似的詞。通常會置有許多題目供人練習,題目會給詳盡的敘述,讓你知道你必須寫出具備什麼功能的程式。你的程式必須 能夠接受題目所規定的指定格式的輸入,依題目指定的格式輸出結果。通常會有幾組作為範例的輸出輸入供參考,也可用作測試程式是否正常運行,且給出預期答 案。
線上批改系統之所以有「批改」二字,是因為你可以將你的程式碼上傳到該網站,它會為你測試你的程式。但是程式是無法判斷程式對錯的,又不可能進行人工檢 測。因此,最常見的方法是,準備一定數量的測試用數據,稱為「測試數據」,又稱「測試資料」或簡稱「測資」,將你的程式編譯並執行後,餵入測試數據,看你 的程式能否在可允許的時間內,產生正確的結果。
線上批改系統會測試你的程式是否能正常編譯,運行過程有無不正常結束 (也就是當掉) 以及能否在時間內,對於給定的測試數據,將結果計算完畢並輸出。最後,如果前面都通過了,就會檢查你的結果是否正確。結果如下表:
Accepted (AC) - 測試結果正確。
Presentation Error (PE) - 測試結果正確,但格式上稍有不符。
Wrong Answer (WA) - 測試結果不正確,缺漏或夾雜不相干的輸出,或格式嚴重不符。
Time Limit Exceeded (TLE) - 程式無法在允許的時間內完成計算。通常是沒寫法,也可能是方法不夠有效率。
Run-Time Error (RE) - 程式不正常結束。通常是當掉,像除以 0 或是拜訪不該拜訪的記憶體位址。
Compilation Error (CE) - 編譯錯誤。可能選錯語言,傳錯檔案,複製不完全,或你的程式碼根本有問題。
它餵入測試數據的方法是,執行你的程式,將存放測試數據的檔案導入至輸入中,並將你所有的輸出導出至檔案,再對該檔案進行核對。
大部份題目會有「多重輸入」。大致有三種形式,題目都會詳述。一種是會在一開始輸入一個數字,代表接下來你必須處理多少組輸入,這種相當容易,先讀完第一 個數字就知道有幾組了。第二種是當特定的輸入出現,比如說輸入物品數是 0 或是 -1 的時候,代表的是輸入已結束。第三種較特別,就是它不會告訴你。你必須自行判斷輸入是否已結束。由於檔案不論再大,都一定有固定的大小。在讀到檔案尾的時 候,scanf() 或其它讀入用的函數,會告訴你已經到檔案尾了。scanf() 是透過回傳 EOF (即 End-of-File) 來告訴你。所以我們可以寫成這樣:
while(scanf("%d", &n) != EOF)
{
}
來做反覆的輸入。while 你可以將它看作是沒有 A 和 C 區段的 for。這樣一來,如果輸入還不是 EOF 就會繼續執行程式。若要在程式執行中手動模擬輸入結束,可以輸入 CTRL+Z。按了之後會顯示 ^Z,按下 ENTER 就相當於遇到 EOF 了。
輸出是否正確,是在程式結束後,才進行判斷,因此留待最後一次輸出,和每讀入一組,便處理後輸出一組,最後得出的結果會完全相同。由於只看輸出,所以你在手動輸入時打入的東西,會確實出現在畫面上,實際上不存在最後的輸出結果中,這點也要注意。
千萬不要輸出任何關於提示輸入的文字,或其它訊息。例如「please enter a number」之類的絕對不要。這夾雜在輸出中只會被認為你的輸出結果是錯誤的。
請務必留意換行問題。每一行的「結束」之時,請一律輸出「\n」。這符號雖被稱為「換行符號」,實質的意義卻不是告知「我們需要新的一行」,而是宣告「目前這一行結束了」。請在每一行的結束之時確實輸出「\n」而不要只在需要新的一行時才輸出。
請務必詳讀題目在輸出格式中,關於「空白行」的敘述。空白行即是什麼都沒有的一行。若是一行之中完全沒有任何東西,直接遇上「\n」的話,就代表它是個空白行。
通常有以下幾種情形,一種是沒特別要求,這種別輸出多餘空白行即可。要是好心怕批改時搞混而每組之間多輸出一行空白行,也會被認定是錯誤。一種是每組數據 「之後」空一個空白行。這意味著最後一組數據「之後」也要空一個空白行,所以一律多空一行即可。一種是每組數據「之間」空一個空白行,這比較麻煩。像是以 EOF 結束輸入的情形,我們不會知道有沒有下一組,所以不能隨意多輸出空白行。幸運的是,我們可以判斷這是不是第一組數據,如果不是的話,在輸出這組結果之前先 輸出一個空白行即可。
判斷方法相當容易。我們用個變數記錄現在是不是第一組數據。一開始還沒輸入時預先設定為「是」,在第一組處理完之後,將這個變數改為「不是」。至於如何使 用變數記錄「是」與「不是」,我們可以用 0 或 1 代表。C 語言中 0 即代表「不是」,1 代表「是」。這樣我們就能夠判斷目前是不是第一組。
int first;
first = 1;
while(scanf("%d", &n) != EOF)
{
....
if(first != 1)
{
....
}
first = 0;
}
如此一來,在第一組時 first 的值會是 1。第二組開始就會是 0。
如果空白行多了或少了,幾乎都會被判成 Wrong Answer。在得到 WA 的結果時,不妨先檢查看看換行是否正確。
當輸出要求在一行中輸出多個數字並以空白隔開時,請詳細按照敘述去做,別空太多格或是完全不空格,也別在一開始或最後一個數字之後,輸出空格。雖然最後一個空白是看不到的,但它實際存在,批改系統是能夠判斷出來的。
請不要在程式中保留 while(1); 之類的程式碼。前面說過這方便我們觀察程式輸出結果,因為它「會讓程式無法自行結束」。前面提到有一種錯誤是「在允許的時間內無法處理完所有數據,輸出結 果並結束程式」,也就是 TLE,如果放了 while(1); 且執行到了的話肯定是「無法在允許時間內結束程式」,因為它根本不可能「自行結束」。我們知道處理完了,所以看完結果後會手動結束它,但是批改系統可不知 道。它可是一板一眼不知變通的。
儘管我們學習的是 C 語言,但目前上傳時,最好在語言部份選擇 C++。UVa 上面使用的是 ANSI C,這版本的編譯器相當嚴格,容易出現編譯錯誤。
這樣一來,我們對批改系統有了初步的認識,也擁有了解決批改系統上的基本題的能力。雖然我們連程式的基本語法都還沒有學全,但從此時開始練習,有助於增進 對這些基本語法中的基本更加了解與熟練,之後學習其它語法會更加輕鬆,也能更快上手。語法是累積的,而不是分開單獨存在的,從根本開始練習有助於學習更進 一步的東西。
請記得保留你每一題的程式碼。若是使用公用電腦,可以使用 E-mail 夾帶程式碼的檔案,寄給自己。未來會有諸多好處。程式碼通常也不大,就算完成了數千道題,每題都寫到檔案大小 10K (這需要 10240 個字) 也不到 100MB。一部小說通常也不到 10 MB以上的,不用擔心硬碟沒地方放遊戲或其它東西。定期把執行檔清理掉即可,留著程式碼的話執行檔要生幾份有幾份。
保留程式碼的用意並非要你用在相似題上。請紮紮實實地從頭完成你的每一道題目,而不要剪剪貼貼的,自己思考整個程式的架構與方法,並自己親手打上每一個 字。這對於寫程式的經驗絕對是有益無害的。你會對語法更加了解,對程式的運作以及之後學到的每個方法更加熟悉,儘管這比較花時間。
即使請教他人也不要流於抄襲,在聽完高人指點與精闢分析之後,試著自己從頭思考一遍,親手實作一次,盡量不要參閱程式碼。程式碼建議在解決之後再作參考, 看看是否有更好的寫法。在自己親手實作前便參考的話,容易受制於殘存的印象,而只是試著「重現」,並非自行思考每一步的意義並寫出來。這樣會比較辛苦,但 是完成後會直接刻在內心,日後更能運用自如。
題目也不要寫過就算了,之後想到或知道更好的做法,或是有別的想法,都可以多寫幾次試試看。題數也並非絕對重要,要在寫的過程慢慢累積經驗,多嘗試多學習。能從寫題目中獲得多少才是最重要的。
自己出個練習題試著寫寫看?寫完隨手測幾個數字發現正確無誤就好了嗎?這樣其實比較辛苦,不如我們找找網路上既有的練習題試試,說不定別人想到我們沒想到 的巧妙題目,寫完了只要上傳程式碼還能自動判斷執行效率以及正確與否,多麼方便啊!這種網站去哪找?網路上現在不少,這裡介紹個我比較熟悉,也相當常見的 網站。
UVa Online Judge
台灣俗稱 ACM 的網站。由來是它收錄了不少 ACM ICPC 競賽的題目。詳細介紹留待之後的文章。網址如下:
http://uva.onlinejudge.org
雖然是英文的,不過也有些好心人翻譯了不少題目出來。網址如下:
http://163.32.78.26/
網站本身不太穩定,如果死掉了可以先用別人架的鏡像站。但是鏡像站的資料較古舊,有些比較新的翻譯可能沒更新到。但也已有相當數量的題目翻譯了。如果原網站沒問題,建議還是不要用鏡像站。以下是其中一個鏡像站:
http://w.csie.org/~b97115/luckycat/
但是並非所有題目均有翻譯。翻譯的速度通常是跟不上寫的速度,也與各譯者擅長與不擅長有關,日後仍有必要直接閱讀英文題目。現階段主要是在這裡可以方便找 到許多難度僅有一顆星的題目。未翻譯的題目中也有許多難度僅有一顆星的程度,但是並不好找,對初學者而言更無從著手。就以目前到這篇為止,也不足以解開所 有一顆星程度的題目。文末會列出此時較適合寫的題目。
首先我們連上 UVa 的網站,左上角登入欄的底下有個 Registre 的連結,點它。Username 是你的帳號,而 Name 是你的名字。如果你沒有使用過它的舊網站,也沒印象持有舊網站 ID 的話,在 Online Judge ID 填上 00000,否則填上舊網站 ID 則可以把舊帳號整合過來。Results Email 則可以自行選擇勾或不勾。勾的話你之後有上傳題目,它會把結果寄到你的信箱。沒有勾的話也能在網站上看到結果,所以不影響。如果不嫌它很煩的話建議是勾一 下,好處是它若發現某道題目需要重新判定大家上傳的程式碼正確與否 (通常是測試不夠嚴謹以致於錯誤的程式碼被判成正確) 的話,在收信時會發現。
之後請到信箱收認證信,收到後就完成註冊了。接下來在 UVa 登入後,就可以上傳你的程式碼了。請注意如果勾選 Remember me 再登入的話,以後有可能導致沒辦法連上。如果遇到這種情形,請開啟 Chrome 的無痕瀏覽,或 Firefox 的私密瀏覽試試,或是把瀏覽器的 cookie 清掉。
目前能解的題目,有以下幾題:
10071
10300
11172
100
488
未列出不代表不能解,這裡只是列出可解的幾道題。但是在開始寫之前,有幾個地方需要特別注意。
這篇文章放在這個順位,理應存在相當多目前難以說明的東西,硬要作說明則會出現不少新東西要記,也有許多很難講明白的地方。這裡已經盡量講得淺白易懂,若一時記不完可以先大致看過,等到寫一寫出問題再回來查。
征服 UVa 的行前準備:了解線上批改系統
首先我們必須了解它的基本規則。這類網站人稱 Online Judge,多譯作「線上批改系統」或類似的詞。通常會置有許多題目供人練習,題目會給詳盡的敘述,讓你知道你必須寫出具備什麼功能的程式。你的程式必須 能夠接受題目所規定的指定格式的輸入,依題目指定的格式輸出結果。通常會有幾組作為範例的輸出輸入供參考,也可用作測試程式是否正常運行,且給出預期答 案。
線上批改系統之所以有「批改」二字,是因為你可以將你的程式碼上傳到該網站,它會為你測試你的程式。但是程式是無法判斷程式對錯的,又不可能進行人工檢 測。因此,最常見的方法是,準備一定數量的測試用數據,稱為「測試數據」,又稱「測試資料」或簡稱「測資」,將你的程式編譯並執行後,餵入測試數據,看你 的程式能否在可允許的時間內,產生正確的結果。
線上批改系統會測試你的程式是否能正常編譯,運行過程有無不正常結束 (也就是當掉) 以及能否在時間內,對於給定的測試數據,將結果計算完畢並輸出。最後,如果前面都通過了,就會檢查你的結果是否正確。結果如下表:
Accepted (AC) - 測試結果正確。
Presentation Error (PE) - 測試結果正確,但格式上稍有不符。
Wrong Answer (WA) - 測試結果不正確,缺漏或夾雜不相干的輸出,或格式嚴重不符。
Time Limit Exceeded (TLE) - 程式無法在允許的時間內完成計算。通常是沒寫法,也可能是方法不夠有效率。
Run-Time Error (RE) - 程式不正常結束。通常是當掉,像除以 0 或是拜訪不該拜訪的記憶體位址。
Compilation Error (CE) - 編譯錯誤。可能選錯語言,傳錯檔案,複製不完全,或你的程式碼根本有問題。
它餵入測試數據的方法是,執行你的程式,將存放測試數據的檔案導入至輸入中,並將你所有的輸出導出至檔案,再對該檔案進行核對。
大部份題目會有「多重輸入」。大致有三種形式,題目都會詳述。一種是會在一開始輸入一個數字,代表接下來你必須處理多少組輸入,這種相當容易,先讀完第一 個數字就知道有幾組了。第二種是當特定的輸入出現,比如說輸入物品數是 0 或是 -1 的時候,代表的是輸入已結束。第三種較特別,就是它不會告訴你。你必須自行判斷輸入是否已結束。由於檔案不論再大,都一定有固定的大小。在讀到檔案尾的時 候,scanf() 或其它讀入用的函數,會告訴你已經到檔案尾了。scanf() 是透過回傳 EOF (即 End-of-File) 來告訴你。所以我們可以寫成這樣:
while(scanf("%d", &n) != EOF)
{
}
來做反覆的輸入。while 你可以將它看作是沒有 A 和 C 區段的 for。這樣一來,如果輸入還不是 EOF 就會繼續執行程式。若要在程式執行中手動模擬輸入結束,可以輸入 CTRL+Z。按了之後會顯示 ^Z,按下 ENTER 就相當於遇到 EOF 了。
輸出是否正確,是在程式結束後,才進行判斷,因此留待最後一次輸出,和每讀入一組,便處理後輸出一組,最後得出的結果會完全相同。由於只看輸出,所以你在手動輸入時打入的東西,會確實出現在畫面上,實際上不存在最後的輸出結果中,這點也要注意。
千萬不要輸出任何關於提示輸入的文字,或其它訊息。例如「please enter a number」之類的絕對不要。這夾雜在輸出中只會被認為你的輸出結果是錯誤的。
請務必留意換行問題。每一行的「結束」之時,請一律輸出「\n」。這符號雖被稱為「換行符號」,實質的意義卻不是告知「我們需要新的一行」,而是宣告「目前這一行結束了」。請在每一行的結束之時確實輸出「\n」而不要只在需要新的一行時才輸出。
請務必詳讀題目在輸出格式中,關於「空白行」的敘述。空白行即是什麼都沒有的一行。若是一行之中完全沒有任何東西,直接遇上「\n」的話,就代表它是個空白行。
通常有以下幾種情形,一種是沒特別要求,這種別輸出多餘空白行即可。要是好心怕批改時搞混而每組之間多輸出一行空白行,也會被認定是錯誤。一種是每組數據 「之後」空一個空白行。這意味著最後一組數據「之後」也要空一個空白行,所以一律多空一行即可。一種是每組數據「之間」空一個空白行,這比較麻煩。像是以 EOF 結束輸入的情形,我們不會知道有沒有下一組,所以不能隨意多輸出空白行。幸運的是,我們可以判斷這是不是第一組數據,如果不是的話,在輸出這組結果之前先 輸出一個空白行即可。
判斷方法相當容易。我們用個變數記錄現在是不是第一組數據。一開始還沒輸入時預先設定為「是」,在第一組處理完之後,將這個變數改為「不是」。至於如何使 用變數記錄「是」與「不是」,我們可以用 0 或 1 代表。C 語言中 0 即代表「不是」,1 代表「是」。這樣我們就能夠判斷目前是不是第一組。
int first;
first = 1;
while(scanf("%d", &n) != EOF)
{
....
if(first != 1)
{
....
}
first = 0;
}
如此一來,在第一組時 first 的值會是 1。第二組開始就會是 0。
如果空白行多了或少了,幾乎都會被判成 Wrong Answer。在得到 WA 的結果時,不妨先檢查看看換行是否正確。
當輸出要求在一行中輸出多個數字並以空白隔開時,請詳細按照敘述去做,別空太多格或是完全不空格,也別在一開始或最後一個數字之後,輸出空格。雖然最後一個空白是看不到的,但它實際存在,批改系統是能夠判斷出來的。
請不要在程式中保留 while(1); 之類的程式碼。前面說過這方便我們觀察程式輸出結果,因為它「會讓程式無法自行結束」。前面提到有一種錯誤是「在允許的時間內無法處理完所有數據,輸出結 果並結束程式」,也就是 TLE,如果放了 while(1); 且執行到了的話肯定是「無法在允許時間內結束程式」,因為它根本不可能「自行結束」。我們知道處理完了,所以看完結果後會手動結束它,但是批改系統可不知 道。它可是一板一眼不知變通的。
儘管我們學習的是 C 語言,但目前上傳時,最好在語言部份選擇 C++。UVa 上面使用的是 ANSI C,這版本的編譯器相當嚴格,容易出現編譯錯誤。
這樣一來,我們對批改系統有了初步的認識,也擁有了解決批改系統上的基本題的能力。雖然我們連程式的基本語法都還沒有學全,但從此時開始練習,有助於增進 對這些基本語法中的基本更加了解與熟練,之後學習其它語法會更加輕鬆,也能更快上手。語法是累積的,而不是分開單獨存在的,從根本開始練習有助於學習更進 一步的東西。
請記得保留你每一題的程式碼。若是使用公用電腦,可以使用 E-mail 夾帶程式碼的檔案,寄給自己。未來會有諸多好處。程式碼通常也不大,就算完成了數千道題,每題都寫到檔案大小 10K (這需要 10240 個字) 也不到 100MB。一部小說通常也不到 10 MB以上的,不用擔心硬碟沒地方放遊戲或其它東西。定期把執行檔清理掉即可,留著程式碼的話執行檔要生幾份有幾份。
保留程式碼的用意並非要你用在相似題上。請紮紮實實地從頭完成你的每一道題目,而不要剪剪貼貼的,自己思考整個程式的架構與方法,並自己親手打上每一個 字。這對於寫程式的經驗絕對是有益無害的。你會對語法更加了解,對程式的運作以及之後學到的每個方法更加熟悉,儘管這比較花時間。
即使請教他人也不要流於抄襲,在聽完高人指點與精闢分析之後,試著自己從頭思考一遍,親手實作一次,盡量不要參閱程式碼。程式碼建議在解決之後再作參考, 看看是否有更好的寫法。在自己親手實作前便參考的話,容易受制於殘存的印象,而只是試著「重現」,並非自行思考每一步的意義並寫出來。這樣會比較辛苦,但 是完成後會直接刻在內心,日後更能運用自如。
題目也不要寫過就算了,之後想到或知道更好的做法,或是有別的想法,都可以多寫幾次試試看。題數也並非絕對重要,要在寫的過程慢慢累積經驗,多嘗試多學習。能從寫題目中獲得多少才是最重要的。
[UVa] 642 - Word Amalgamation
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//字元比較
int n,m;
char word[2000][10], sorted[2000][10], scramble[2000][10], sorted2[2000][10];
int cmp_char(const void* _a, const void* _b){
char* a = (char*)_a;
char* b = (char*)_b;
return *a-*b;
}
//字串比較
int cmp_string(const void* _a, const void* _b){
char* a = (char*)_a;
char* b = (char*)_b;
return strcmp(a,b);
}
int main(){
n = 0;
//輸入字典單字,將每個單字存入word[n]中
for(;;){
scanf("%s", word[n]); //會自動以空白分隔單字
if(word[n][0]=='X'&&word[n][1]=='X'&&word[n][2]=='X'&&word[n][3]=='X'&&word[n][4]=='X'&&word[n][5]=='X')break;
n++;
}
//題目的OUTPUT中有敘述,輸出要按字典排序,故此排序為必要
qsort(word, n, sizeof(word[0]), cmp_string); //幫所有單字排序(由小到大),引入cmp_string為qsort必要之參照
for(int i = 0; i<n; i++){
strcpy(sorted[i], word[i]);
qsort(sorted[i], strlen(sorted[i]), sizeof(char), cmp_char); //幫每個單字的字母各自排序
}
//輸入欲檢查之單字
char s[10];
while(scanf("%s", s)!=EOF && s[0]!='X') {
qsort(s, strlen(s), sizeof(char), cmp_char); //將其內的字母做排序
int found = 0;
for(int i = 0; i < n; i++){
if(strcmp(sorted[i], s) == 0) {
found = 1;
printf("%s\n", word[i]);
}
}
if(!found) printf("NOT A VALID WORD\n");
printf("******\n");
}
return 0;
}
2014年8月22日星期五
[UVa] 10082 - WERTYU
參考並引用了下列連結的說明:http://www.cnblogs.com/oomusou/archive/2007/03/04/663234.html
上述的s是個char array,含12個byte(包含結尾\0),"Hello World"對s來說是initializer,將字元一個一個地copy進s陣列。
char s[]為陣列,雖然s = &s[0],但s是『常數』,恆等於&s[0]無法改變,但char *s為pointer,指向s[0],但卻是變數,可以任意改變,故可用*s++任意更改pointer值。
char s[] = "Hello World";
上述的s是個char array,含12個byte(包含結尾\0),"Hello World"對s來說是initializer,將字元一個一個地copy進s陣列。
char *s = "Hello World";上述的s是一個pointer指向char,由於"Hello World"本身就是一個string literal,所以s指向"Hello World"這個string literal的起始記憶體位置。
char s[]為陣列,雖然s = &s[0],但s是『常數』,恆等於&s[0]無法改變,但char *s為pointer,指向s[0],但卻是變數,可以任意改變,故可用*s++任意更改pointer值。
#include <stdio.h>
#include <string.h>
char *s = "`1234567890-=QWERTYUIOP[]\\ASDFGHJKL;'ZXCVBNM,./";
int main(){
int i,c;
while((c = getchar())!=EOF){
for(i=1;s[i] && s[i]!=c;i++); /*輸入字串逐字檢查*/
if(s[i])putchar(s[i-1]); /*輸出前一個字元*/
else putchar(c); /*如果非其中字元,輸出原本字元(空白)*/
}
return 0;
}
2014年8月18日星期一
[UVa] 11530 - SMS Typing
/*
要注意,Judge測試的Case數很大
*/
要注意,Judge測試的Case數很大
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int i,j,cases=0,count=0;
int main(){
scanf("%d",&cases);
char c[1000]={'\0'};
getchar();
for(i=0;i<cases;i++){
fgets(c,sizeof(c),stdin);
count=0;
for(j=0;j<sizeof(c);j++){
if(c[j]=='a' || c[j]=='d' || c[j]=='g' || c[j]=='j' || c[j]=='m' ||
c[j]=='p' || c[j]=='t' || c[j]=='w' || c[j]==' ')count++;
if(c[j]=='b' || c[j]=='e' || c[j]=='h' || c[j]=='k' ||
c[j]=='n' || c[j]=='q' || c[j]=='u' || c[j]=='x')count+=2;
if(c[j]=='c' || c[j]=='f' || c[j]=='i' || c[j]=='l' ||
c[j]=='o' || c[j]=='r' || c[j]=='v' || c[j]=='y')count+=3;
if(c[j]=='s' || c[j]=='z')count+=4;
}
printf("Case #%d: %d\n",i+1,count);
for(j=0;j<1000;j++)c[j]='\0'; /*renew the array!*/
}
/*
for(i=0;i<cases;i++){
printf("Case #%d: %d\n",i+1,s[i]);
}
*/
return 0;
}
2014年8月14日星期四
[UVa] 10038 - Jolly Jumpers
宣告check[3001]陣列的用意是,兩者先減後得到的絕對差值x,
於check[x]放入1,如此只要檢查每個check陣列的元素是否為1,
即可確認所有差值是否為1至n-1了!
#include <stdio.h> #include <stdlib.h> int n; int main(){ while(scanf("%d",&n)!=EOF){ int i,t=1; int s[3001]={0},check[3001]={0}; for(i=1;i<=n;i++){ scanf("%d", &s[i]); } for(i=1;i<=n-1;i++){ check[abs(s[i+1]-s[i])]=1; } for(i=1;i<=n-1;i++){ if(check[i]==0)t=0; } if(t==0)printf("Not jolly\n"); if(t==1)printf("Jolly\n"); } return 0; }
2014年8月13日星期三
[POJ] 2386 - Lack Counting
USACO 2004 November
#include <stdio.h>
int N, M;
char field[105][105]; /*宣告庭院*/
void dfs(int x, int y){
field[x][y] = '.';
int dx,dy,nx,ny; /*必須在裡面宣告?*/
for(dx = -1; dx<=1; ++dx){
for(dy = -1; dy<=1; ++dy){
nx = x+dx;
ny = y+dy;
if(nx>=0 && nx < N && ny>=0 && ny<M && field[nx][ny] == 'W')
dfs(nx, ny); /*判斷nx及ny是否在庭院,且判斷是否為積水*/
}
}
return ;
}
int main(){
while(scanf("%d%d", &N, &M)!=EOF){
int i,j;
for(i=0; i<N; ++i)
scanf("%s",&field[i]);
int res = 0;
for(i=0; i<N; ++i){
for(j=0; j<M; j++){
if(field[i][j] == 'W'){
dfs(i,j);
res++;
}
}
}
printf("%d\n", res);
}
}
int N, M;
char field[105][105]; /*宣告庭院*/
void dfs(int x, int y){
field[x][y] = '.';
int dx,dy,nx,ny; /*必須在裡面宣告?*/
for(dx = -1; dx<=1; ++dx){
for(dy = -1; dy<=1; ++dy){
nx = x+dx;
ny = y+dy;
if(nx>=0 && nx < N && ny>=0 && ny<M && field[nx][ny] == 'W')
dfs(nx, ny); /*判斷nx及ny是否在庭院,且判斷是否為積水*/
}
}
return ;
}
int main(){
while(scanf("%d%d", &N, &M)!=EOF){
int i,j;
for(i=0; i<N; ++i)
scanf("%s",&field[i]);
int res = 0;
for(i=0; i<N; ++i){
for(j=0; j<M; j++){
if(field[i][j] == 'W'){
dfs(i,j);
res++;
}
}
}
printf("%d\n", res);
}
}
2014年8月12日星期二
[UVa] 488 - Triangle Wave
#include <stdio.h>
#include <stdlib.h>
int c; /*case*/
int i,j,tmp;
int main(){
scanf("%d",&c); /*輸入case數*/
int S[2][c]; /*宣告 case * 2 的矩陣,擺放每個case的Amplitude及Frequency值*/
for(i=0;i<c;i++){
scanf("%d%d", &S[0][i], &S[1][i]);
while(S[1][i]>0){
for(j=1 ; j<=S[0][i] ; j++){
for(tmp=0; tmp<j; tmp++)
printf("%d",j);
printf("\n");
}
for(j=S[0][i]-1 ; j>0 ; j--){
for(tmp=0; tmp<j; tmp++)
printf("%d",j);
printf("\n");
}
S[1][i]--;
if(S[1][i]>0)printf("\n");
}
if(i<(c-1))printf("\n");
}
return 0;
}
2014年8月10日星期日
Setup MinGW (GCC Compiler in Windows)
Download and Install
MinGW Homepage: http://www.mingw.org/
Download MinGW installer: http://sourceforge.net/projects/mingw/files/Installer/
In MinGW Installation Manager window, we can only choose mingw32-gcc-g++ (The GNU C++ Compiler) then Apply Change to setup.
Environment Settings
- Right-click on your "My Computer" icon and select "Properties".
- Click on the "Advanced" tab, then on the "Environment Variables" button.
- You should be presented with a dialog box with two text boxes. The top box shows your user settings. The PATH entry in this box is the one you want to modify. Note that the bottom text box allows you to change the system PATH variable. You should not alter the system path variable in any manner, or you will cause all sorts of problems for you and your computer!
- Click on the PATH entry in the TOP box, then click on the "Edit" button
- Scroll to the end of the string and at the end add
;<installation-directory>\bin
- press OK -> OK -> OK and you are done.
2014年8月9日星期六
[POJ] 3617 - Best Cow Line
#include <stdio.h>
#include <stdlib.h>
int N, cnt = 0, i;
char S[2001];
void solve(){
int a = 0, b = N-1;
while(a <= b){
int left = 0;
for (i = 0; a+1<=b; i++){
if(S[a+i] < S[b-i]){
left = 1;
break;
}
else if(S[a+i] > S[b-i]){
left = 0;
break;
}
}
if(left)putchar(S[a++]);
else putchar(S[b--]);
cnt++;
if(cnt %80 == 0)putchar('\n');
}
putchar('\n');
}
int main(){
while(scanf("%d",&N)!= EOF){
for(i=0; i<N; i++)
{
getchar(); //避免前面的scanf遺留的換行(\n)讀入
scanf("%c", &S[i]);
}
solve();
}
return 0;
}
2014年8月7日星期四
新的開始
學生時期接觸的多半是電機方面的知識,多半是自動控制居多,所撰寫的程式也僅包含了影像傳輸、人機介面和機械控制的部分。
在網路上找到幾個網站,再配上幾本書籍,希望在鑽研許久之後,可以提升自己的程式能力,起碼不要和資訊專業的人相差太多,對未來工作相信也會有所幫助。
§參考資料
§Online Judge
若有增加,再來補齊。
在網路上找到幾個網站,再配上幾本書籍,希望在鑽研許久之後,可以提升自己的程式能力,起碼不要和資訊專業的人相差太多,對未來工作相信也會有所幫助。
§參考資料
- 演算法筆記:http://www.csie.ntnu.edu.tw/~u91029/index.html
- C++程式設計:http://www.tcgs.tc.edu.tw/~sagit/cpp/
- Cplusplus :http://www.cplusplus.com/
- 建中資訊科培訓網:http://pisces.ck.tp.edu.tw/~peng/index.php?year=2009
- C語言學習筆記:http://openhome.cc/Gossip/CGossip/
- Beej's Guide to Unix Network Programming: http://beej-zhtw.netdpi.net/
§Online Judge
- PKU Judge:poj.org
- UVa Online Judge:http://uva.onlinejudge.org/
若有增加,再來補齊。
2014年8月1日星期五
How to set up the TrackPoint in Linux in Thinkpad X40
Configuration using xinput
If you want to modify changes on the fly, you can do so with
xinput
(part of the optional xorg-x11-apps rpm on Fedora).
Note that these changes are not saved when the xserver is restarted. However, you can add the lines e.g. in your .xsessionrc
(depends on your distribution) so they are executed every time X starts.
To query the available options
xinput list-props "TPPS/2 IBM TrackPoint"
More information can be found in the man-pages for evdev
man evdev
To enable vertical scrolling
xinput set-prop "TPPS/2 IBM TrackPoint" "Evdev Wheel Emulation" 1 xinput set-prop "TPPS/2 IBM TrackPoint" "Evdev Wheel Emulation Button" 2 xinput set-prop "TPPS/2 IBM TrackPoint" "Evdev Wheel Emulation Timeout" 200
To enable horizontal scrolling in addition to vertical scrolling
xinput set-prop "TPPS/2 IBM TrackPoint" "Evdev Wheel Emulation Axes" 6 7 4 5
To enable middle button emulation (using left- and right-click simultaneously)
xinput set-prop "TPPS/2 IBM TrackPoint" "Evdev Middle Button Emulation" 1 xinput set-prop "TPPS/2 IBM TrackPoint" "Evdev Middle Button Timeout" 50
文章參考來源:http://www.thinkwiki.org/wiki/How_to_configure_the_TrackPoin
訂閱:
文章 (Atom)
-
因為先前寫UVa時,檔案名稱有時會花心思改,有時就直接把題目名稱加上.cpp就貼上了 導致現在有不同的格式出現 現在要處理的事情很簡單 1. 去除空白 2. 將底線 ( _ ) 換成dash ( - ) 經過一番查詢,終於發現最簡單的方法 - re...
-
文章出處: http://infbugs.blogspot.tw/2011/12/c_20.html 謝謝沙耶,解答了我長久以來對於 input/output 的疑惑。 C 語言入門 - 在線上批改系統練功 如何練習使用基本語法 自己出個練習題試著寫...
-
一開始用數學方法推斷得出,設輸入為n k為在n的前一斜線列數,故只要找到 (1+k)*k/2 < n 的最大k值,即可判定 k%2 == 1 => ((2*n)-(k*k)-k)/2 / ((k*k)+(3*k)-(2*n)+4)/2 k%2 ==...