5:Permutation

Description

 

We all know that , when there are n positive integers (namely 1…n) , we can use these n integers to construct n! kinds of permutations . Sort these permutations in lexicographic order . For example , when n = 3 , we can permute 1 2 3,1 3 2,2 1 3, 2 3 1, 3 1 2 , 3 2 1 these 6 kinds of permutations.

Now , we want to know , with the given permutation , calculate the next k permutation . If the permutation is the last permutation in order , its next permutation is the first permutation , namely 1 2 3 … n.

e.g. when n = 3 , k = 2 , giving the permutation 2 3 1 , thus its next 1 permutation is 3 1 2 , its next 2 permutation is 3 2 1 , so the answer is 3 2 1 .

Input

 

The first line is a positive integer m , indicating the number of test cases . Then m test cases . In every test case , the first line is 2 positive integers n (1 <= n < 1024) and k (1 <= k <= 64) ; the second line are n positive integers , which is one of the  “ 1 2 3 … n”  s’ permutation.

 

Output

 

For each test case , print one line , n numbers , with spaces separating every number , indicating the given permutation ‘s next k permutation.

 

Sample Input

 

3

3 1

2 3 1

3 1

3 2 1

10 2 

1 2 3 4 5 6 7 8 9 10

Sample Output

 

3 1 2

1 2 3

1 2 3 4 5 6 7 9 8 10


自己寫的程序(非常麻煩,其實算法的原理很簡單,我真是個笨鱉.....):

package OJ;

import java.util.*;

public class P5_temp {   //Permutation

	public static void main(String[] args) {
		class group {
			int[] group;
			
			public group(int[] group) {
				this.group = group;
			}
			
			public int[] get() {
				return group;
			}
		}
		
		Scanner in = new Scanner(System.in);
		int caseNum = in.nextInt();
		in.nextLine();
		//這裏需要一些東西
		ArrayList<group> result = new ArrayList<group>();
		
		for(int i = 0; i < caseNum; i++) {
			int orderNum = in.nextInt();
			//收集原來的排列
			int[] order = new int[orderNum];
			//往下變化的數量
			int nextNum = in.nextInt();
			in.nextLine();//////////////////////////////////
			for(int j = 0; j < orderNum; j++) {
				order[j] = in.nextInt();
			}
			//收集數據結束
			//開始進行往下進行變化
			order = findPermutation(order, nextNum, order.length-1);		
			result.add(new group(order));
			if(i < caseNum-1)
				in.nextLine();
		}
		
		for(group g : result) {
			int[] t = g.get();
			for(int i = 0; i < t.length; i++){
				if(i == t.length -1){
					System.out.println(t[i]);
					System.out.println();
				}
				else {
					System.out.print(t[i] + " ");
				}
			}
 		}
	}

	public static int[] findPermutation(int[] num, int nextNum, int end) {//nextNum是需要變化的次數
		boolean is = false;
		int loc = end -1;
		TreeSet<Integer> od = new TreeSet<Integer>();
		//一邊比較,一邊排序
		for(; end >= 0; end--,loc--) {   //第一個循環
			boolean skip = false;          //是否跳出第一個循環的標誌
			//假如前一個比後面有序序列的最大值小,則交換,每交換一次,則改變次數+1
			if(loc < 0)
				od.add(num[end]);
			
			else {
				od.add(num[end]);
				if(num[loc] < od.last()) {
					int bigger = od.subSet(od.higher(num[loc]), od.last()+1).size();
					if(bigger*calculateGroupNum(od.size()) < nextNum) {  //假如後續的所有變化都不能滿足變化數
						nextNum = nextNum - bigger*calculateGroupNum(od.size());
						continue;
					}
					else {  //假如後續的變化可以滿足nextNum的要求
						Iterator<Integer> iter = od.iterator();
			            while(iter.hasNext()) {   //第二個循環,不斷的從後續隊列中抽取比num[loc]大的元素
			            	int y = iter.next();
			            	if(y > num[loc]){
								nextNum--;	
								if(nextNum == 0) {  //假如nextNum爲0,退出循環,!!!!返回數組(需要將od中的覆蓋到原數組)!!!!!!
									od.add(num[loc]);
									num[loc] = y;
									od.remove(y);
									skip = true;
									break;
								}
								else {
								    int cg = calculateGroupNum(od.size()) - 1;
									if(cg < nextNum) {  //假如之後的序列不能將nextNum變爲<=0,則不用進行具體的變化
										nextNum = nextNum - cg;
										continue;
									}
									else if(cg == nextNum) { //返回數組(將od中的數以倒敘覆蓋到原數組)應該!!!!!!
										nextNum = 0;
										is = true;
										skip = true;
										od.add(num[loc]);
										num[loc] = y;
										od.remove(y);
										break;
									}
									else {  //這時可以進行具體的變化(因爲nextNum<排列組合數)
					            		od.add(num[loc]);
										num[loc] = y;
										od.remove(y);
										for(int i = num.length-od.size(); i < num.length ; i++)
											num[i] = od.pollFirst();
										num = findPermutation(num, nextNum, num.length-1);
										break;
									}
								}
			            	}
			            }
					}        
				}
			}
			
//				//假如前一個比後面的有序序列的最大值大,則將num[loc]加入到有序序列
//				else {
//					od.add(num[loc]);
//				}
			if(skip == true)
				break;
		}
		
		if(nextNum == 0 && end > 0 && is == false){ //這就是發現了最終的答案
			for(int i = num.length-od.size(); i < num.length ; i++)
				num[i] = od.pollFirst();
			return num;
		}	
		else if (nextNum == 0 && end > 0 && is == true) {
			for(int i = num.length-od.size(); i < num.length ; i++)
				num[i] = od.pollLast();
			return num;
		}
		else if (end == -1 && nextNum >0) {  //這是需要循環到整體最小的序列,重新開始
			for(int i = 0; i < num.length ; i++)
				num[i] = od.pollFirst();
			nextNum--;
			if(nextNum == 0) 
				return num;
			else
				return findPermutation(num, nextNum, num.length - 1);
		}
		else 
			return null;
	}
	
	public static int calculateGroupNum(int Num) {  //計算排列組合的最大值
			int sum = 1;
			for(int i = 1; i <= Num; i++)
				sum *= i;
			return sum;
	}

}


題目要求的算法:實際上使用c++STL的next_permutation方法,可以很快的得出結果。下面是關於這個函數的介紹:

next_permutation函數實現原理如下:

在當前序列中,從尾端往前尋找兩個相鄰元素,前一個記爲*i,後一個記爲*ii,並且滿足*i < *ii。然後再從尾端尋找另一個元素*j,如果滿足*i < *j,即將第i個元素與第j個元素對調,並將第ii個元素之後(包括ii)的所有元素顛倒排序,即求出下一個序列了。




發佈了24 篇原創文章 · 獲贊 0 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章