1. 程式人生 > 其它 >演算法實驗三-遞迴與分治

演算法實驗三-遞迴與分治

一、實驗目的:

理解遞迴演算法的思想和遞迴程式的執行過程,並能熟練編寫遞迴程式。

掌握分治演算法的思想,對給定的問題能設計出分治演算法予以解決。

二、實驗環境:

VC6.0

三、實驗內容:

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. 編寫完整的主函式,分別記錄利用上述遞迴函式求第47, 48, 49, 50, 51,52個Fibonacci數所花費的時間。
#include<stdio.h>

#include<time.h>

int fi(int n)

{

 if(n<=1) return (n);

 else

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

}


int main()

{ int i;

 double X;

 X= clock()/CLOCKS_PER_SEC;

 for(i=47;i<=52;i++)

 { X= clock()/CLOCKS_PER_SEC;

  printf("計算第%d個數   所計算得的結果為%ld\t",i,fi(i));

  X= clock() / CLOCKS_PER_SEC-X;

  printf("計算第%d個的需要的時間為:%f\n",i,X);

 }

}
  1. 將遞迴函式改為尾遞迴,或者是遞推函式,求第47, 48, 49, 50, 51,52個Fibonacci數所花費的時間,觀察效率是否得到提高。

#include<stdio.h>
#include<time.h>

double fi(int n)
{
    double F;
    int Fa,Fb;
    Fa=0;
    Fb=1;
    for(int i=0;i<n;i++){
        F=Fa+Fb;
        Fb=Fa;
        Fa=F;
    }

    return F;
}

int main()
{
    int i;
     double X;
     X= clock()/CLOCKS_PER_SEC;
     for(i=47;i<=52;i++)
     { 
        X= clock()/CLOCKS_PER_SEC;
        printf("計算第%d個數   所計算得的結果為%ld\t",i,fi(i));
        X= clock() / CLOCKS_PER_SEC-X;
        printf("計算第%d個的需要的時間為:%f\n",i,X)
       }
      return 0;
}

2.角谷定理。

輸入一個自然數n,若n為偶數,則把它除以2,若n為奇數,則把它乘以3加1。用新得到的數重複以上步驟,直到值為1為止。求經過多少次看得到自然數1。

#include <iostream>
using namespace std;
int w = 0;
int jg(int n){
	if (n == 1)
	{
		return 0;
	}	
	else if (n % 2 == 0)
	{	n /= 2;
		cout<<n<<" ";
		if(w==9)
			cout<<endl;
		w++;
		return jg(n); 
	} 
	else
	{	n = n * 3 + 1;
		cout<<n<<" ";
		if(w==9)
			cout<<endl;
		w++;
		return jg(n); 
	} 
}
int main() {
	int n;
	cin >> n;
	jg(n);
	cout << 經過"<<w <<"次"<< endl;
	return 0;
}

實驗結果:

3.走臺階

有n級臺階,可以一步上一個臺階,也可以一步上兩個臺階,編寫程式,計算共有幾種不同的走法。

#include <iostream>
using namespace std;
int w = 0;
int Step(int n){
	if (n < 0)
		return 0;
	if (n == 0){
		w++;
		return 0;
	}
	Step(n - 1);
	Step(n - 2);
	return 0;
}
int main() {
	int n;
	cin >> n;
	Step(n);
	cout << "有"<<w <<"種走法"<< endl;
	return 0;
}

實驗結果:

4. 半數集問題

問題描述:給定一個自然數n,由n開始可以依次產生半數集set(n)中的數如下:

(1)

(2) 在n的左邊加上一個自然數,但該自然數不能超過最近新增的數的一半;

(3) 按此規則進行處理,直到不能再新增自然數為止。

例如,set(6)={6,16,26,126,36,136},半數集set(6)中有6個元素。

輸入:整數n(0<n<1000)

輸出:半數集set(n)中的元素個數。

請設計遞迴函式,求出set(n)的個數,並分析演算法時間複雜度,對演算法進行改進,用程式驗證遞迴演算法,以及改進之後的演算法。

#include<iostream>
#include<time.h>
using namespace std;
int set(int n)
{
      int a=1;
      if(n>1)
            for(int i=1;i<=n/2;i++)
                  a=a+set(i);
      return a;
}
int main()
{
      int n;
      cout<<"請輸入n值:";
      cin>>n;
       X= clock()/CLOCKS_PER_SEC;
      cout<<"set("<<n<<")的個數為:"<<set(n)<<endl;
      X= clock() / CLOCKS_PER_SEC-X;
      cout<<"花費的時間為:"<<X<<endl;
      return 0;
}

實驗結果:

改進:

#include<iostream>
#include<cstring>
#include<time.h>
using namespace std;
int a[1000];
long set(int n)
{
      int an=1;
      if(a[n]>0)
            return a[n];
      for(int i=1;i<=n/2;i++)
                  an=an+set(i);
      a[n]=an;
      return an;
}
int main()
{
      int n;
      double X;
      cout<<"ÇëÊäÈënÖµ£º";
      cin>>n;
      memset(a,0,sizeof(a));
      a[1]=1;
      X= clock()/CLOCKS_PER_SEC;
      cout<<"set("<<n<<")的個數為:"<<set(n)<<endl;
      X= clock() / CLOCKS_PER_SEC-X;
      cout<<"花費的時間為:"<<X<<endl;
      return 0;
}

實驗結果: