1. 程式人生 > >演算法分析 遞迴與分治

演算法分析 遞迴與分治

1.  Fibonacci數列

   無窮數列1,1,2,3,5,8,13,21,34,55,……,稱為Fibonacci數列。它可以遞迴地定義為:

第n個Fibonacci數可遞迴地計算如下:

int fibonacci(int n)

   {

       if (n <= 1) return 1;

       return fibonacci(n-1)+fibonacci(n-2);

   }

  1. 編寫完整的主函式,分別記錄利用上述遞迴函式求第45,46,47,48個Fibonacci數所花費的時間。
#include<stdio.h>

#include<time.h>

long fibonacci(int n)

{

       if (n <= 1)

                 return 1;

       return fibonacci(n-1)+fibonacci(n-2);

}

void main()

{

  int N,i;

  double s;

  clock_t start , stop;

  for(i=45;i<=48;i++){

  start=clock();

  fibonacci(i);

  printf("第%d個執行時間",i);

  stop=clock();

   s=(stop-start)/CLK_TCK;

  printf(" %lfs\n",s);

  }

}

(2)將遞迴函式改為尾遞迴,或者是遞推函式,求第45,46,47,48個Fibonacci數所花費的時間,觀察效率是否得到提高。

#include<stdio.h>
#include<time.h>
long tailfib(int n,int acc1,int acc2) {
    if (n < 2) {
        return acc1;
    }
     
    return tailfib(n-1,acc2,acc1 + acc2);
}
void main()
{
  int N,i;
  double s;
  clock_t start , stop;
  for(i=45;i<=48;i++){
  start=clock();
  printf("%d:%lld",i,tailfib(i,1,1));
  stop=clock();
   s=(stop-start)/CLK_TCK;
  printf(" %lfs\n",s);
  }
}

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
 
int a[100];
int n;
 
int max;   //當前最大元素 
int f(int n)  
{
	int min;   //當前最小元素 
	if(n==2)     //只有兩個元素時,直接求解(最小問題) 
	{
		if(a[n-2]>a[n-1]){
			max=a[n-2],min=a[n-1];
		}
		else{
			max=a[n-1],min=a[n-2]; 
		}
		return min;
	}
	else
	{ 
		min=f(n-1);		//遞迴找第二大元素 
		if(a[n-1]>max){ 
			min=max,max=a[n-1];   //找到前面n-1個元素中最大和第二大元素時
		}
		if(a[n-1]<max&&a[n-1]>min){
			min=a[n-1]; //再與第n個元素比較找第二大元素 
		}
		return min;   //返回結果 
	}
}
 
void random() 
{
	srand(time(NULL));
	for(int i=0;i<n;i++)
	{
		a[i]=1+rand()%100;
	}
}
 
int main()
{
	
	int s;
	printf("請輸入元素的個數n:");
	scanf("%d",&n);
	random();
	printf("\n這n個數依次為: ");
	for(int j=0;j<n;j++)
		printf("%d\t",a[j]);
	s=f(n);
	printf("\n\n這n個數中第二大元素為:%d\n",s);
	return 0;
}

5. 棋盤覆蓋問題

   在一個2k×2k 個方格組成的棋盤中,恰有一個方格與其它方格不同,稱該方格為一特殊方格,且稱該棋盤為一特殊棋盤。在棋盤覆蓋問題中,要用圖示的4種不同形態的L型骨牌覆蓋給定的特殊棋盤上除特殊方格以外的所有方格,且任何2個L型骨牌不得重疊覆蓋。

演算法描述如下:

引數說明:

子棋盤:由棋盤左上角的座標tr,tc和棋盤大小size表示。

特殊方格:在二維陣列中的座標位置是(dr,dc)。

#include<stdio.h>
int Martrix[100][100];
int tile=0;   //整形變數,記錄L型骨牌的數量
void chessBoard(int tr, int tc, int dr, int dc, int size) //tr和tc分別是棋盤左上角方格的行號,列號; dr和dc分別代表特殊方格的行號,列號
{
    int s,t;
    if (1 == size) return;

    s = size/2; //分割棋盤
    t = ++ tile; //L型骨牌號,初始值為0


    if (dr < tr + s && dc < tc +s)  //用L型骨牌號覆蓋左上角子棋盤
    {
        chessBoard(tr,tc,dr,dc,s);//特殊方格在此棋盤中
    }
    else //特殊方格不在此棋盤中用,t號L型骨牌覆蓋右下角
    {
        Martrix[tr+s-1][tc+s-1] = t;   //覆蓋本子棋盤中的其餘方格
        chessBoard(tr,tc,tr+s-1,tc+s-1,s);
    }

    if (dr < tr + s && dc >= tc + s )  //用L型骨牌號覆蓋右上角子棋盤
    {
        chessBoard(tr,tc+s,dr,dc,s); //特殊方格在此棋盤中
    }
    else //特殊方格不在此棋盤中用,t號L型骨牌覆蓋左下角
    {
        Martrix[tr+s-1][tc+s] = t; //覆蓋本子棋盤中的其餘方格
        chessBoard(tr,tc+s,tr+s-1,tc+s,s);
    }

    if (dr >= tr + s && dc < tc + s) //用L型骨牌號覆蓋右上角棋盤
    {
        chessBoard(tr+s,tc,dr,dc,s); //特殊方格在此棋盤中
    } 
    else  //特殊方格不在此棋盤中,用t號L型骨牌覆蓋左下角
    {
        Martrix[tr+s][tc+s-1] = t;  //覆蓋本子棋盤中的其餘方格
        chessBoard(tr+s,tc,tr+s,tc+s-1,s);
    }

    if (dr >= tr + s && dc >= tc + s)  //用L型骨牌號覆蓋右上角子棋盤
    {
        chessBoard(tr+s,tc+s,dr,dc,s); //特殊方格在此棋盤中
    } 
    else   //特殊方格不在此棋盤中用t號L型骨牌左上角
    {
        Martrix[tr+s][tc+s] = t;  //覆蓋本子棋盤中的其餘方格
        chessBoard(tr+s,tc+s,tr+s,tc+s,s);
    }

}

int main()
{
    int size,r,c,row,col;
     printf("設定棋盤大小:");
    scanf("%d",&size);
	printf("\n輸入特殊方格位置:(x,y)  ");
    scanf("%d%d",&row,&col);
    chessBoard(0,0,row,col,size);

    for (r = 0; r < size; r++)
    {
        for (c = 0;c<size; c++)
        {
            printf("%2d ",Martrix[r][c]);
        }
        printf("\n");
    }

    return 0;
}