演算法競賽入門經典第2版 第2章 迴圈結構
阿新 • • 發佈:2018-12-11
學習目標
掌握for迴圈、while迴圈、do-while迴圈的使用方法
學會使用計數器和累加器
學會用輸出中間結果的方法除錯
學會用計時函式測試程式效率
學會用重定向、fopen的方式讀寫檔案
瞭解演算法競賽對檔案讀寫方式和命名的嚴格性
記住變數在賦值之前的值是不確定的
學會使用條件編譯指示構建本地執行環境
學會用編譯選項-Wall獲得更多的警告資訊
2.1 for迴圈
例2-1 aabb
#include <stdio.h> int main() { /* 方法一 int i,j,m,n; for(i=1;i<10;i++) { for(j=0;j<10;j++) { m = i*1100+j*11; n = floor(sqrt(m)+0.5); //浮點運算可能存在誤差,為了減小誤差的影響,所以加上0.5,以便四捨五入。 if(n*n == m) { printf("%d\n",m); } } }*/ //方法二:列舉平方根,從而避免開平方操作 int i,n,a,b; for(i=1;;i++) { n = i*i; if(n>10000) { break; } if(n<1000) { continue; } a = n/100; b = n%100; if(a/10 == a%10 && b/10 == b%10) { printf("%d\n",n); } } return 0; }
2.2 while迴圈和do-while迴圈
例2-2 3n+1問題
#include <stdio.h> int main() { int n,count = 0; scanf("%d",&n); long long n1 = n; //int為32位的,long long為64位的,但它的輸入輸出比較複雜 while(n1>1) { if(n1%2 != 0) { n1 = 3*n1+1; }else{ n1 = n1/2; } count++; } printf("%d\n",count); return 0; }
/* 1.注意乘法溢位的問題
2.long long型
例2-3 近似計算
#include <stdio.h> int main() { int i; double sum = 0,term; for(i=0;;i++) { term = 1.0/(2*i+1); //注意應用1.0,使能夠算出來浮點數 if(i%2 == 0) sum += term; else sum -= term; if(term<1e-6) break; } printf("%f\n",sum); return 0; }
2.3 迴圈的代價
例2-4 階乘之和
#include <stdio.h> #include <time.h> int main() { const int MOD = 1000000; int n,i,a=1,b,sum=0; scanf("%d",&n); for(i=1;i<=n;i++) { a *= i; b = a%MOD; sum += b; } printf("%d\n",sum); printf("Time used = %.2f\n",(double)clock() / CLOCKS_PER_SEC); return 0; } /* 1.clock()函式返回程式目前為止執行的時間。常數CLOCK_PER_SEC和作業系統有關,不要直接使用clock()的返回值,而應總是除以這個常數。 2.上述得出的時間包括了鍵盤輸入的時間。為了避免輸入資料的時間影響測試結果,是使用一種稱為“管道"的小技巧。 3.嘗試很多次之後發現,從第五項開始,後面所有的項都不會影響和的末六位數字,所以只需在最前面加上“if(n>5) n=25;" 效率和溢位都不會存在問題。
例2-5 資料統計
#include <stdio.h> #define N 1000000 int main() { int max=-N,min=N,a,sum=0,i=0; while(scanf("%d",&a) == 1) { sum += a; if(a<min) min = a; if(a>max) max = a; i++; } printf("%d %d %.3f\n",max,min,(double)sum/i); retnrn 0; } //重定向版 #define LOCAL #include <stdio.h> #define N 1000000 int main() { #ifdef LOCAL freopen("input.txt","r",stdin); freopen("output.txt","w",stdout); #endif // LOCAL int max=-N,min=N,a,sum=0,i=0; while(scanf("%d",&a) == 1) { sum += a; if(a<min) min = a; if(a>max) max = a; i++; } printf("%d %d %.3f\n",max,min,(double)sum/i); return 0; } //fopen版 #include <stdio.h> #define N 1000000 int main() { FIFE *fin,*fout; fin = fopen("data.in","rb"); fout = fopen("data.out","wb"); int max=-N,min=N,a,sum=0,i=0; while(fscanf(fin,"%d",&a) == 1) { sum += a; if(a<min) min = a; if(a>max) max = a; i++; } fprintf(fout,"%d %d %.3f\n",max,min,(double)sum/i); fclose(fin); fclose(fout); return 0; } /* 1.輸入資料,按enter鍵,並未顯示結果,不是程式執行太慢,而是仍在等待輸入。在Windows下,輸入完畢後先按Enter鍵,再按Ctrl+Z鍵, 最後再按Enter鍵即可結束輸入。在Linux下,輸入完畢後按Ctrl+D鍵即可結束輸入。 2.使用檔案最簡單的方法是使用輸入輸出重定向,只需在main函式的入口處加上以下兩條語句: freopen("input.txt","r",stdin); freopen("output.txt","w",stdout); 3.如果比賽要求用檔案輸入輸出,但禁止使用重定向的方式,則可以使用fopen。 4.重定向和fopen兩種方法各有優劣。 重定向:寫起來自然、簡單,但是不能同時讀寫檔案和標準輸入輸出。 fopen:寫法稍顯繁瑣,但是靈活性比較大(例如,可以反覆開啟並讀寫檔案)。如果想把fopen版的程式改成讀寫標準輸入輸出, 只需賦值"fin=stdin;fout=stdout;"即可,不要呼叫fopen和fclose。 */
例2-6 資料統計II
#include <stdio.h> #define N 10000000 int main() { int n,a,k=0,i,max=-N,min=N,sum; while(scanf("%d",&n) == 1 && n) { max=-N,min=N; sum = 0; for(i=0;i<n;i++) { scanf("%d",&a); sum += a; if(a>max) max = a; if(a<min) min = a; } if(k) printf("\n"); printf("Case %d: %d %d %f\n",++k,min,max,(double)sum/n); } return 0; }