寫了幾個關於全排列的東西,然後就接觸到了康拓排列。之前對於全排列的非遞迴演算法耿耿於懷,乙隻不能找到好的方式。現在好了,有了康拓,什麼都解決了。
我們先來看乙個簡單的例子,就是如何遞迴的求全排列。
private static void recursionpermutation(string s, int k)
system.out.println();
} for(int i=k;i
上述就是求全排列的遞迴演算法了,那麼這裡引入乙個概念,就是康拓排列,什麼是康拓排列呢?乙個陣列,求它的全排列,然後按照從小到大的順序(這個可以是字典順序啊,或者你定義的其他順序都行)排好,那麼這就是康拓排列。比如,它的康拓排列就是,,,,,。
康拓排列有乙個前提是裡面的元素不能有重複的!
這是乙個經典問題,前面已經減了什麼事康拓排列了,那麼給你乙個排列,讓你求它的下乙個排列是什麼,這個演算法應該怎麼寫呢?比如上述例子,的下乙個排列是。
這個例子的演算法如下,不多說,自己慢慢看。
public class nextpermutation ;
int next = nextpermutation(nums);
system.out.println(arrays.tostring(next));
} public static int nextpermutation(int nums)
} //交換兩個元素
swap(nums,i,partitionnumbersite);
//逆序排序
for(int j=pivot,k=nums.length-1;j
康拓排列有乙個典型的應用就是判斷乙個排列的位置,給你乙個排列),那麼這個排列肯定是第乙個啊。那麼對於四個數字的呢?5個數字的,它有在哪乙個呢?
這個的演算法的思想如下:
先了解什麼是康拓展開
形如下式的炸開叫做康拓展開,
x=an*(n-1)!+an-1*(n-2)!+...+ai*(i-1)!+...+a2*1!+a1*0!
ai為整數,並且0<=ai於是我們建立3個桶,我們知道3個桶裡面已經放好數字了,分別是3,2,1.現在我們想知道這個數字是第幾大的。怎麼辦呢,我們看第乙個桶,第乙個桶中的數字是3,但是第乙個桶我們知道如果你來放的話,是可以放1,2,3三個數字的,那麼這裡面比三小的數字有1,和 2連個,於是,由1或者2開頭的全排列都比3開頭的全排列要小(100多肯定小於300多啊),於是我們知道由1開頭的有1*2!(階乘)個,由2開頭的有1*2!(階乘)個,所以,這裡有2*2!個。再看第二個桶,同理,第二個桶被放了2,此時第乙個桶已經放好3了,所以第二個桶你來放的話,只能放2和1。我們知道,32*肯定比31*要大,而滿足這個條件的,只有1*1!(階乘)種。最後第三個桶,已經沒有比它小的了,所以只能乘以0了。於是就是2*2!+1*1!+0*0!=5.所以這個排列是第6大的(別忘記加1)
再舉個例子:1324是排列數中第幾個大的數:第一位是1小於1的數沒有,是0個,0*3!,第二位是3小於3的數有1和2,但1已經在第一位了,所以只有乙個數2,1*2! 。第三位是2小於2的數是1,但1在第一位,所以有0個數,0*1!,所以比1324小的排列有0*3!+1*2!+0*1!=2個,1324是第三個大數。
**非常簡單,如下
public static int cantor(int nums)
}result+=temp*factorial(length-i-1);
} return result+1;
}
這個題目有兩種做法,一種是執行k-1次nextpermutation,另外一種就是使用康托排列了。重點講康托排列。
如何找出第16個(按字典序的)的全排列?
1. 首先用16-1得到15
2. 用15去除4! 得到0餘15
3. 用15去除3! 得到2餘3
4. 用3去除2! 得到1餘1
5. 用1去除1! 得到1餘0
有0個數比它小的數是1,所以第一位是1
有2個數比它小的數是3,但1已經在之前出現過了所以是4
有1個數比它小的數是2,但1已經在之前出現過了所以是3
有1個數比它小的數是2,但1,3,4都出現過了所以是5
最後乙個數只能是2
所以排列為1 4 3 5 2
下面是兩種方法的**:
private static void getpermutationbynext(int i, int j)
//別忘記最後乙個元素
result[n-1]=list.get(0);
return result;
}
康拓拓展和逆拓展解決全排列問題
在解決排列問題時,一般有以下問題 給你乙個排列,問你是第幾個排列 給你乙個排列,問下乙個排列是多少 給你乙個排列,問前乙個排列是多少 給你乙個數i,問第i個排列是多少 一般暴力的話使用遞迴加回溯都能解決,但是時間複雜福比較高,遞迴多了棧也會溢位。這裡使用康拓展開的思想,具體思路。看不懂沒關係,繼續看...
關於全排列問題的總結(康托展開)
今天做usaco上一道題的時候用到了這個東西,當時覺得麻煩直接用map寫了,然後仔細研究了一下,康托展開與其逆展開,個人覺得會在節省空間和表示狀態上有比較大的幫助。先來正展開吧,即給定排列序列,求是第幾個排列,看序列中的第k位,假設序列長度為n,那麼,k位之後的各位數全排列有 n k 種,然後看k之...
康托展開 全排列的本質
參考鏈結 x a n n 1 a n 1 n 2 a i i 1 a 1 0 1.求乙個排列是原排列的按字典序的第幾個排列。include include using namespace std int fac 階乘 intcantor int a,int n x fac n i 1 smaller...