1. 程式人生 > >演算法競賽入門經典第2版 第2章 迴圈結構

演算法競賽入門經典第2版 第2章 迴圈結構

學習目標

  掌握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;
}