標籤(空格分隔): oj_演算法
全排列在很多程式都有應用,是乙個很常見的演算法,常規的演算法是一種遞迴的演算法,這種演算法的得到基於以下的分析思路。 給定乙個具有n個元素的集合(n>=1),要求輸出這個集合中元素的所有可能的排列。
例如,如果集合是,那麼這個集合中元素的所有排列是,顯然,給定n個元素共有n!種不同的排列,如果給定集合是,可以用下面給出的簡單演算法產生其所有排列,即集合(a,b,c,d)的所有排列有下面的排列組成:
(1)以a開頭後面跟著(b,c,d)的排列
(2)以b開頭後面跟著(a,c,d)的排列
(3)以c開頭後面跟著(a,b,d)的排列
(4)以d開頭後面跟著(a,b,c)的排列,這顯然是一種遞迴的思路,於是我們得到了以下的實現:
即:對於有n個元素的集合的排列t(n)時,分別以集合的每個元素作為第乙個位置的元素,然後求剩下n-1個元素的全排列t(n-1);重複遞迴,知道集合只有乙個元素t(1),其全排列為元素本身。
所以:
1. 遞迴方程為: t(n)=n*t(n-1)
2. 遞迴結束條件: 元素個數為1,結束;
演算法實現:
/*************************************
function: 求字串的全排列
input param:
char *a :字串
k:遞迴層次(確定第k個位置的元素)
n:字串元素個數
**************************************/
void permutation(char* a,int k,int n)
} }
對乙個給定資料進行全排列,在各種場合經常會用到。組合數學中,生成全排列的方法有很多,盧開澄老師的《組合數學》中就介紹了三種:序數法,字典序法,臨位互換法等。其中以字典序法由於演算法簡單,並且使用的時候可以依照當前狀態獲取下乙個狀態,直到所有排列全部完成,方便在程式中隨要隨用,應用比較廣泛,stl中的next_permutation也是使用此法。
字典序,顧名思義就是按照字典的順序(a-z, 1-9)。以字典序為基礎,我們可以得出任意兩個數字串的大小。比如 「1」 < 「12」<」13」。 就是按每個數字位逐個比較的結果。對於乙個數字串,「123456789」, 可以知道最小的串是 從小到大的有序串「123456789」,而最大的串是從大到小的有序串「*987654321」。這樣對於「123456789」的所有排列,將他們排序,即可以得到按照字典序排序的所有排列的有序集合。
如此,當我們知道當前的排列時,要獲取下乙個排列時,就可以範圍有序集合中的下乙個數(恰好比他大的)。比如,當前的排列時「123456879」, 那麼恰好比他大的下乙個排列就是「123456897」。 當當前的排列時最大的時候,說明所有的排列都找完了。
字典序法求全排列步驟:
設p是1~n的乙個全排列:p=p1p2……pn=p1p2……pj-1pjpj+1……pk-1pkpk+1……pn(即開始時字串必須進行公升序排列,使其成為全排列的第乙個串(最小串))
1. 從排列的右端開始,找出第乙個比右邊數字小的數字的序號j(j從左端開始計算),即j=max(右邊的數從右至左是遞增的,因此k是所有大於pj的數字中序號最大者)
3. 對換pj,pk
4. 再將pj+1……pk-1pkpk+1……pn倒轉得到排列p』=p1p2…..pj-1pjpn…..pk+1pkpk-1…..pj+1,這就是排列p的下乙個排列。
5. 返回至步驟1重複進行,直到步驟1,i=0,依然未找到,此時所有全排列都找完,其數字串從大到小排序
#include求全排列,遞迴演算法效率太低,所以採用非遞迴的字典序法實現排列。這個演算法已經在c++的stl中實現;#include
using
namespace
std;
/*******************************
function:字典序全排列
********************************/
void lexicographicalorderpermutation(string &input,vector
&output)
sort(input.begin(), input.end());
output.push_back(input);//字典序全排列的第乙個值
string::iterator it_j,it_k,it_i = input.end()-2;
while (it_i!=input.end())
while (it_i!=input.end()&&(*it_j < *it_i));//2. 在pj的右邊的數字中,找出所有比pj大的數中最小的數字pk,即 k=max
it_k = it_i - 1;
swap(*it_j, *it_k);//3. 對換pj,pk
reverse(it_j + 1, input.end());//4. 倒轉pk+1....pn
output.push_back(input);//5.得到乙個全排列,輸出
it_i = input.end() - 2;//重新從最右邊開始搜尋
}else
}}int main()
} while (a.size());
system("pause");
return
0;}
在中,有兩個庫函式:pre_permutation與next_permutation
重點解析next_permutation;
函式原型:
template
bool next_permutation(
bidirectionaliterator _first,
bidirectionaliterator _last
);template
bool next_permutation(
bidirectionaliterator _first,
bidirectionaliterator _last,
binarypredicate _comp
);
next_permutation(first,last),求的字串的下乙個字典序排列,如成功,返回true,失敗返回false.
例如:字串1234'
其下乙個字典序為1243,即在初始字串為1234時,執行next_permutation,返回true,同時字串被改為
1243`.而pre_permutation與next_permutation剛好相反,其求取字串字典序的上乙個排列。
由以上可知,如想求得乙個字串的全排列,只需將字串公升序排列(所得字串為字典序排列的最小排列),然後反覆執行next_permutation,直到返回為false,即所有字串倒序,已找到最大字典序排列。
求字典序全排列**如下:
#include
#include
#include
using
namespace
std;
void lexicographicalorderpermutationbystl(string &input, vector
&output)
while (next_permutation(it_first,it_last));
}int main()
} while (a.size());
system("pause");
return
0;}
參考:
1. 2.
3. 字典序法:
演算法 全排列
從n個不同元素中任取m m n 個元素,按照一定的順序排列起來,叫做從n個不同元素中取出m個元素的乙個排列。當m n時所有的排列情況叫全排列。用演算法分別實現全排列,其中n個元素儲存在乙個長度為n的陣列中。實現全排列之前,先看一下對進行全排列的一種方法 從圖中可以看出,我們首先從n個元素中取出乙個元...
全排列演算法
1.遞迴全排列 分別將每個位置交換到最前面位,之後全排列剩下的位。遞迴全排列 1 2 3 4 5 1,for迴圈將每個位置的資料交換到第一位 swap 1,1 5 2,按相同的方式全排列剩餘的位 2.字典序全排列演算法 對給定的字符集中的字元規定了乙個先後關係,在此基礎上規定兩個全排列的先後是從左到...
全排列演算法
1.遞迴生成1 n的全排列 示例程式 include using namespacestd void print intn,int a,int cur int main int num while cin num int a 30 print num,a,0 return 0 void print ...