生成可重集的排列

刘汝佳在算法竞赛入门经典,http://book.douban.com/subject…,的 118 页提到生成一个可重集的全排列问题,跟上次的 生成一个字符串的全排列 很相像,但是写法却巧妙很多

#include <stdio.h>

void quick_sort(int a[], int left, int right)
{
	int i=left, j=right;
	int povit = a[(i+j)/2];
	while (i <= j)
	{
		while (a[i] < povit)
		{
			i++;
		}
		while (a[j] > povit)
		{
			j--;
		}
		if (i <= j)
		{
			int tmp = a[j];
			a[j] = a[i];
			a[i] = tmp;
			i++;
			j--;
		}
	}
	if (left < j)
	{
		quick_sort(a, left, j);
	}
	if (i < right)
	{
		quick_sort(a, i, right);
	}
}

void print_permutation(int n, int *p, int *a, int cur)
{
	int i, j;
	if (cur == n)
	{
		for (i=0; i<n; i++)
		{
			printf("%d ", a[i]);
		}
		printf("n");
	}
	else
	{
		for (i=0; i<n; i++)
		{
			if (!i || p[i]!=p[i-1])
			{
				int c1=0, c2=0;
				for (j=0; j<cur; j++)
				{
					if (a[j] == p[i])
					{
						c1++;
					}
				}
				for (j=0; j<n; j++)
				{
					if (p[i] == p[j])
					{
						c2++;
					}
				}
				if (c1 < c2)
				{
					a[cur] = p[i];
					print_permutation(n, p, a, cur+1);
				}
			}
		}
	}
}

int main()
{
	int n;
	while (scanf("%d", &n) != EOF)
	{
		int *p = new int[n];
		for (int i=0; i<n; i++)
		{
			scanf("%d", &p[i]);
		}
		quick_sort(p, 0, n-1);
		int *a = new int[n];
		print_permutation(n, p, a, 0);
		delete[] p;
		delete[] a;
	}
	return 0;
}

输入输出

3
1 2 3
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
3
1 2 2
1 2 2
2 1 2
2 2 1

需要说明的是,他的这种全排列生成需要数组有序,于是顺便就当作复习了一遍快排了

Leave a Reply

Your email address will not be published. Required fields are marked *