排列POJ1833

题目描述:

解题思路:该问题的解题关键在于确定一个排列生成下一个排列的算法。举例说明,以4721653为例。下一个排列需要比4721653大,且为所有比4721653大的排列中最小的一个。因此,最简单的想法是先确定一个比4721653大的数字的集合,然后对该集合中的数字进行排序,从中找出最小的一个数字。找到一个包含若干个比4721653大的数字且包含最小数字的集合的最简单方法是,从低位到高位找一个降序的相邻数字,从该位置到最右侧位置挑一个恰好比当前位置数字大的数字,与其进行交换。例如,找到16,调换3和1的位置,得到下一个排列4723651。这样调换后,能得到一个比当前排列更大的排列,但未必是所有排列中最小的一个,但该数字给出了一个正确答案的上界。因此,还需要增加一个操作,使得到的排列是所有比当前排列大的排列中最小的一个。于是,对于调换过的位置,从低的位置开始,对后续数字做升序排列,如对651排列得到4723156,即可得到下一个排列。

#include<cstdio>

int a[1025] = {0};

void NextPermutation(int size)
{
	int flag = size - 1;
	int temp;
	int i;
	//从Xn开始向左查找,直到找到某个位置Xj,满足Xj-1<Xj 
	while(a[flag-1] > a[flag] && flag != 0)
	{
		flag--;
	}
	//如果X1,X2,...,Xn已经是降序排列,则其下一个排序为Xn,Xn-1,...,X1 
	if(flag == 0) 
	{
		for(i = 0; i < size; i++)
			a[i] = i+1;
		return;
	}
	//在Xj,Xj+1,...,Xn中找到最小的比Xj-1大的数,将这个数和Xj-1互换
	for(i = size - 1; i >= flag; i--) 
	{
		if(a[i] > a[flag - 1])
		{
			temp = a[flag - 1];
			a[flag - 1] = a[i];
			a[i] = temp;
			break;
		}
	}
	//将位置j到位置n的所有数从小到大重新排序,得到最终的下一个序列
	while(size - 1 > flag) 
	{
		temp = a[size - 1];
		a[size - 1] = a[flag];
		a[flag] = temp;
		flag++;
		size--;
	}
}

int main()
{
	int m,n,k;
	int i;
	scanf("%d",&m);
	while(m)
	{
		scanf("%d%d",&n,&k);
		//给定排列中的n个数X1,X2,X3,...,Xn
		for(i = 0; i < n; i++)
			scanf("%d",&a[i]);  
		for(i = 0; i < k; i++)
			NextPermutation(n);
		for(i = 0; i < n; i++)
			printf("%d ",a[i]);
		printf("\n");
		m--;
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41045071/article/details/81608773