分治法的思想:將原問題分解為幾個規模較小但類似於原問題的子問題,遞歸的求解這些子問題,然后再合並這些子問題的解來建立原問題的解。
分治法在每層遞歸是遵循的三個步驟:
(1)分解原問題為若干個子問題,這些子問題是原問題的規模較小的實例。
(2)解決這些子問題,隊規的求解各個子問題,當子問題規模足夠小的時候,直接求解。
(3)合並這些子問題的解構成原問題的解。
顯然歸並排序是一個非常經典規矩的分治法的例子,鑒於之前已經寫過一篇關於歸並排序的博文,這里不在使用歸並排序作為例子。
注意分治法的每一層遞歸中的第一步分解,可能產生兩個子問題(如歸並排序、二分查找等),也可能產生多個子問題(如排列、組合等),產生兩個子問題的時候當然比較容易理解,而產生多個子問題的時候需要使用環循羅列這些子問題。
下面就以排列和組合算法為例,介紹產生多個子問題的分治算法。
一、排列
問題:輸入一個字符串,打印出該字符串中字符的所有排列。
分析:利用分治法的思想,
(1)先將原問題分解,假如輸入的字符串長度是n,那么第一次選擇可能是第一個字符、也可能是第二個、。。。也可能是第n個,但是不管是哪一個,只要選出第一個字符,就可以在剩下的n-1個字符里面繼續選擇一個了,所以需要將原問題分解為n個子問題(每個子問題為第一步選擇的是i,然后再對除了i之外的字符進行全排列),到現在可以發現如果直接按照順序分解之后,對除了i之外的字符進行全排列,不是那么容易實現遞歸,於是想到將每個元素(包括第一個元素)都與第一個元素交換,然后分解成的子問題就是先將每個元素與第一個元素交換並選出,然后對第二個到最后的所有元素全排列。注意每次個子問題考慮完之后需要將交換的元素換回。
(2)利用遞歸解決每個子問題
(3)當所有問題都解決的時候,子問題的解組合起來就是原問題的解了
如:輸入字符串為abc ,排列函數為permutation()那么分解成的子問題為a+permutation(bc)、b+permutation(ac)、c+permutation(ab)
1 #include "stdafx.h" 2 #include<iostream> 3 using namespace std; 4 void print(char *str) 5 { 6 char *p=str; 7 while(*p) 8 { 9 cout<<*p<<' '; 10 p++; 11 } 12 } 13 void bianli(char *str,int begin,int length) 14 { 15 char temp; 16 int i; 17 if(begin==length-1) 18 { 19 print(str); 20 cout<<endl; 21 return ; 22 } 23 //可以選取某一個值(包括begin自己)與begin的位置交換,然后對剩下的字符全排列 24 //所以對於每一個位置要么選擇先交換,然后遞歸,要么選擇不交換(即交換兩次) 25 for(i=begin;i<length;i++) 26 { 27 temp=str[begin]; 28 str[begin]=str[i]; 29 str[i]=temp; 30 31 bianli(str,begin+1,length); 32 33 temp=str[begin]; 34 str[begin]=str[i]; 35 str[i]=temp; 36 } 37 } 38 39 int _tmain(int argc, _TCHAR* argv[]) 40 { 41 char str[4]="123"; 42 bianli(str,0,3); 43 return 0; 44 }
二、組合
問題:找出從自然數1、2、3。。。n中任取r個元素的所有組合
分析:
1、分解:與排列不同,組合里每個元素在一種只出現一次,所以並不需要交換元素,而是每次從n個數中按照某種順序取一個元素,然后考慮全面了即可,如每次取一個最大值,那么只要元素個數>k則是子問題的一種,剩下的思想和排列差不多。
1 #include<iostream> 2 using namespace std; 3 int a[100];//用於存放組合的結果 4 void zuhe(int n,int k) 5 { 6 for(int i=n;i>=k;i--)//順序選取組合中最大的數 7 { 8 a[k]=i; 9 if(k>1) 10 { 11 zuhe(i-1,k-1); 12 } 13 else 14 { 15 for(int i=1;i<=a[0];i++) 16 { 17 cout<<a[i]<<" "; 18 } 19 cout<<endl; 20 } 21 } 22 } 23 int main() 24 { 25 int n,k; 26 cin>>n>>k; 27 a[0]=k; 28 zuhe(n,k); 29 return 0; 30 }