1. 程式人生 > >演算法競賽入門經典(第二版)第二章迴圈結構程式設計例題與提示下

演算法競賽入門經典(第二版)第二章迴圈結構程式設計例題與提示下

2.3 迴圈的代價

  • 例題2-4階乘之和

輸入n,計算s=1!+2!+3!+…+n!。n<=le-6。
樣例輸入:
10
樣例輸出:
37913

//第一個版本
int main()
{
    int n,s=0;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        int factorial=1;
        for(int j=1;j<=i;j++)
        {
            factorial*=j;
        }
        S
+=factorial; printf("%d\n",s%1000000); } }
  1. 要計算只包含加法,減法和乘法的整數表示式除以正整數n的餘數,可以在每步計算之後對n取餘,結果不變
//第二個版本
#include<time.h>
#include<stdio.h>
int main()
{
  const int MOD=1000000;//常量定義改善了程式的可讀性
  int n,s=0;
  scanf("%d",&n);
  for(int i=1;i<=n;i++)
  {
      int factorial=1;
      for
(int j=1;j<=i;j++) { factorial=(factorial*j%MOD); } s=(s+factorial)%MOD; } printf("%d\n",s);//其實從第五項開始後面的所有項都不會影響和的末6位數字這樣就可解決效率和溢位 printf("time used=%.2f\n",(double)clock()/CLOCKS_PER_SEC);//計時器的使用 return 0; }
  1. 很多程式的執行時間與規模n存在著近似的簡單關係。可以通過計時函式來發現或驗證這一關係

2.4演算法競賽中的輸入輸出框架

  • 例題2-5 資料統計

輸入一些整數求出它們的最小值,最大值和平均值(保留三位小數)。輸入保證這些數都是不超過1000的整數
樣例輸入:
2 8 3 5 1 7 3 6
樣例輸出:
1 8 4.375

//有bug版本
#include<stdio.h>
int main()
{
    int x,n=0,min,max,s=0;
    while(scanf("%d",&x)==1)//scanf函式返回的是成功輸入的變數個數,                            
                            //當輸入結束時scanf函式無法再次讀取x將返回0
                            //按下enter建並不意味著輸入的結束
    {
        s+=x;
        if(x<min)  min=x;//在使用前未賦值
        if(x>max)  max=x;
        n++;
    }
    printf("%d %d %.3f\n",min,max,(double)s/n);
    return 0;
    //第一種方法是定義一個很大的常數如inf=1000000000,然後讓max=-inf而min=inf
    //另一種就是先讀取一個整數x然後令max=min=x
}
  1. 在Windows下輸入完畢後先按enter鍵再按ctrl+z鍵,最後再按enter鍵即可輸入結束。在linux下輸入完畢後按ctrl+d鍵即可結束輸入
  2. 變數在未賦值之前的值是不確定的。特別地,它不一定等於0.
  3. 請在比賽之前瞭解檔案讀寫的相關規定:是標準輸入輸出,還是檔案輸入輸出?如果是檔案輸入輸出,是否禁止用重定向方式訪問檔案

請不要犯以下錯誤
1:程式存為t1.c(應該改為test.c)
2:從input.txt讀取資料(應該從test.in讀取)
3:從test.in讀取資料(拼寫錯誤)
4:資料寫到test.ans(副檔名錯誤,應該是test.in讀取)
5:資料寫到c:\contest\test.out(不能加路徑哪怕是相對路徑。檔名應該只有test.out)

//這是一份典型的比賽程式碼(重定向版)
#include<stdio.h>
#define LOCAL
#define INF 1000000000
int main()
{
    #ifdef LOCAL//重定向的部分
    freopen("data.in","r",stdin);
    freopen("data.out","w",stdout);
    #endif // LOCAL
    int x,n=0,min=INF,max=-INF,s=0;
        while(scanf("%d",&x)==1){
           s+=x;
        if(x<min)  min=x;
        if(x>max)  max=x;
        /*
    printf("%d,%d,%d\n",x,min,max);*///也是一個重點
        n++;  
        }
    printf("%d %d %.3f\n",min,max,(double)s/n);
    return 0;
}
  1. 在演算法競賽中有經驗的選手往往會使用條件編譯指令並且將重要的測試語句註釋掉而非刪除
//fopen版本即要求檔案輸入輸出但禁止重定向的方式
#include<stdio.h>
#define INF 1000000000
int main()
{
FILE *fin,*fout;
fin=fopen("data.in","rb");
fout=fopen("data.out","wb");
    int x,n=0,min=INF,max=-INF,s=0;
        while(fscanf(fin,"%d",&x)==1){
           s+=x;
        if(x<min)  min=x;
        if(x>max)  max=x;
        n++;
        }
    fprintf("%d %d %.3f\n",min,max,(double)s/n);
    fclose(fin);
    fclose(fout);
    return 0;
}
  1. 在演算法競賽中如果不允許使用重定向方式讀寫資料應使用fopen和fscanf/fprintf進行輸入輸出
  • 例題2-6 資料統計||

輸入一些整數求出它們的最小值,最大值和平均值(保留三位小數)。輸入保證這些數都是不超過1000的整數
輸入包含多組資料,每組資料第一行是整數個數n第二行是n個整數。n=0為輸入結束標記,程式應當忽略這組資料。相鄰兩組資料之間應輸出一個空行
樣例輸入:
8
2 8 3 5 1 7 3 6
4
-4 6 10 0
0
樣例輸入:
case 1:1 8 4.375

case 2:-4 10 3.000

//有bug
    #include<stdio.h>
    #define INF 1000000000
    int main()
    {
        int x,n=0,min=INF,max=-INF,s=0,kase=0;//min和max沒用重置導致bug//kase為了格式需求
        while(scanf("%d",&n)==1&&n)//為了魯棒性
        {
            int s=0;//把main函式裡定義的“遮蔽了”
            for(int i=0;i<n;i++)
            {
                scanf("%d",&x);
                s+=x;
                if(x<min)min=x;
                if(x>max)max=x;
            }
            if(kase)printf("\n");
            printf("case %d:%d %d %.3f\n",++kase,min,max,(double)s/n);

        }
        return 0;

    }
  1. 在演算法競賽中,偶爾會出現輸入輸出錯誤的情況。如果程式魯棒性強有時能在資料有瑕疵的情況下仍然給出正確的答案。程式的魯棒性在工程中也非常重要
  2. 再多資料的題目中常見錯誤:在計算完一組資料後某些變數沒有重置,影響到下組資料的求解
  3. 當巢狀的兩個程式碼塊中有同名變數時,內層的變數會遮蔽外層變數,有時會引起十分隱蔽的錯誤