【演算法複習四】計算複雜性與演算法分析—演算法分析

來源:互聯網
上載者:User

一,產生函數與遞推

遞推關係舉例

【例1】Hanoi問題:這是個組合數學中的著名問題。N個圓盤依其半徑大小,從下而上套在A柱上,如示。每次只允許取一個移到柱B或C上,而且不允許大盤放在小盤上方。若要求把柱A上的n個盤移到C柱上請設計一種方法來,並估計要移動幾個盤次。現在只有A、B、C三根柱子可用。

|
| |

|
| |

A
B C


第一步把A中N-1個移動到B(藉助C)

第二步把A中最下一個移動到C

第三步把B中移動到C(藉助A)


演算法複雜度:

h(n)表示n個盤子所需要轉移次數。

h(n)=2h(n-1)+1

h(1)=1


遞迴演算法:

#include <iostream> using namespace std; int num=0;void Move(int n,char x,char y) {    num++;   cout<<"把"<<n<<"號從"<<x<<"挪動到"<<y<<endl; } void Hannoi(int n,char a,char b,char c)//把n個盤子從a移動到c 藉助b {      if(n==1)          Move(1,a,c);      else      {          Hannoi(n-1,a,c,b); //把n-1個盤子從a移動到b 藉助c         Move(n,a,c);          Hannoi(n-1,b,a,c); //把n-1個盤子從b移動到c 藉助a     } } int main() {      cout<<"以下是 3 層漢諾塔的解法:"<<endl;      Hannoi(7,'a','b','c');      cout<<"輸出完畢!共需要次數:"<<num<<" 次"<<endl;      return 0; } 

【例2】排錯問題.n個有序的元素應有個不同的排列,如若一個排列使得所有的元素都不在原來的位置上,則稱這個排列為錯排;有的叫重排。

以1,2,3,4四個數的錯排為例,分析其結構,找出規律性的東西來。

1)1 2的錯排是唯一的,即2 1。

2)1 2 3的錯排有3 1 2,2 3 1。這二者可以看作是1
2錯排,3分別與1,2換位而得的。


2 1 32與3換位3 1 2

2 1 3 1與3換位2 3 1

3)1,2,3,4的錯排

4 3 2 1,4 1 2 3,4 3 1 2,

3 4 1 2,3 4 2 1,2 4 1 3,

2 1 4 3,3 1 4 2,2 3 4 1。

第一列是4分別與1,2,3互換位置,其餘兩個元素錯排,由此產生的。

第二列是4分別與3,1,2(123的一個錯排)的每一個數互換而得到的

分析:

設n個數1,2,…,n錯排的數目為Dn,任取其中一數 i,數i分別與其他的n-1個數之一互換,其餘n-2個數進行錯排,共得 (n-1)Dn-2個錯排。另一部分位元i以外的n-1個數進行錯排,然後 i 與其中每個數互換得(n-1)Dn-1個錯排。

Dn=(n-1)(Dn-1 + Dn-2) D1=0 D2=1

Dn - nDn-1=(-1) `n


二,遞迴演算法的結構

遞迴結構定義

在進行遞迴演算法的設計時,通常先寫出問題的遞迴定義,遞迴定義由基本項和歸納項兩部分組成。

•基本項,也就是遞迴出口。它描述了一個或幾個遞迴過程的終止狀態。所謂終止狀態指的是不需要繼續遞迴而直接求解的狀態。

•歸納項,也稱為遞迴過程。它描述了如何?從目前狀態到終止狀態的變化。

#include <iostream>using namespace std;int multiplication(int n){if(n==1)return 1;return n*multiplication(n-1);}int main(){cout<<"10的階乘為:"<<multiplication(10)<<endl; return 0;} 

• 基於遞迴的插入排序演算法

#include <iostream>using namespace std;void in_rec (int A[],int n)// 基於遞迴的插入排序演算法{  int a,k; if(n<1) return ;         in_rec (A,n-1);//歸納項,否則,對前面的n-1個元素排序      a = A[n];  // 把第n元素插入合適位置           k = n -1;        while ((k>=0)&&(A[k]>a)) {  A[k+1] = A[k];     k = k - 1;       }         A[k+1] = a;} int main(){int a[5]={3,2,1,4,5};in_rec (a,5);for(int i=0;i<5;++i)cout<<a[i]<<"  ";cout<<endl;return 0;}

三,組合演算法分析

1)全排列演算法

•模型對應

•序數法

•字典序法
•中介數法

•換位法

例題:1 2 3 4 5 6 7 8 9 字典序全排列,求8 3 9 6 4 7 5 2 1的下一個排列

分析:一個全排列可看做一個字串,字串可有首碼、尾碼。所謂一個的下一個就是這一個與下一個之間沒有其他的。這就要求這一個與下一個有儘可能長的共同首碼,也即變化限制在儘可能短的尾碼上。

例如,839647521是1--9的排列。1—9的排列最前面的是123456789,最後面的是987654321,從右向左掃描若都是增的,就到了987654321,也就沒有下一個了。否則找出第一次出現下降的位置。

解答:    1、搜尋末端的最長遞降序列。
2、記緊挨著該序列左邊的數為 a。
3、在該序列中從右至左尋找首個大於 a 的數記為 b。
4、交換 a、b,反轉原序列被 b 換入後的新序列。

(輸出全排列)演算法:

#include <stdio.h> int n = 0; void swap(int *a, int *b) { int m; m = *a; *a = *b; *b = m; } void perm(int list[], int k, int m) { int i; if(k > m) { for(i = 0; i <= m; i++) printf("%d ", list[i]); printf("\n"); n++; } else { for(i = k; i <= m; i++) { swap(&list[k], &list[i]); perm(list, k + 1, m); swap(&list[k], &list[i]); } } } int main() { int list[] = {1, 2, 3, 4, 5}; perm(list, 0, 4); printf("total:%d\n", n); return 0; } 

(輸出下一個)演算法:

#include <iostream>  using namespace std;  void swap(int* x,int* y)  {      int temp;      temp=*x;      *x=*y;      *y=temp;  }  void reverse(int *first,int *last)  {      --last;      for(;first<last;first++,last--)          swap(first,last);  }    bool nextpermutation(int* first,int* last)  {      if(first==last) return false; //為空白      if(first+1==last) return false; //只有一個元素      int* i=last;      --i;  //最後一個元素     for(;;){          int* ii=i; //後一個元素 --i;//前一個元素          if(*i<*ii){ //前<後且相鄰              int* j=last;              while(!(*i<*--j));//從後向前找第一個大於i的數                                      swap(i,j); //交換*i,*j              reverse(ii,last); //反向排列[ii,last)              return true;          }          if(i==first){//前一元素已指向首元素,反轉整個區間,無下一排列              reverse(first,last);              return false;          }      }  }  //輸出結果8 3 9 6 5 1 2 4 7   int main()  {      int d[]={8,3,9,6,4,7,5,2,1};      if(nextpermutation(d,d+9))      {          for(int i=0;i<9;i++)              cout<<d[i]<<" ";          cout<<endl;      }      return 0;  }    

2)中介數

在[1,n]的全排列中,nn-1…
321是最後一個排列,其中介數是(n-1,n-2,...,3,2,1)。而其序號為
1*1!+2*2!+……(n-1)!

計算給定排列的序號

8 3 9 6 4 7 5 2 1的序號即先於此排列的排列的個數。將先於此排列的排列按首碼分類

將8!,7!,…,1!前面的係數抽出,放在一起得到7 2 6 4 2 3 2 1。

7 2 6 4 2 3 2 1是計算排列8 3
9 6 4 7 5 2 1的序號的中間環節,我們稱之為中介數。

※這是一個很有用的概念。

【例12】由中介數推出排列的演算法,例如由中介數7
2 6 4 2 3 2 1(8個數)推算出全排列:8 3 9 6 4 7 5 2 1

方法一: 推導

p1 p2 p3 p4 p5 p6 p7 p8 p9

8                                 2   1

8   3                            2   1

8   3          4                2   1

8   3  9     4                 2   1

…… …… ……

其他詳細方法參見博文
http://blog.csdn.net/tianshuai11/article/details/7520370

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.