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)的所有元素颠倒排序,即求出下一个序列了。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值