#P2093. 桐桐的全排列.填空题

桐桐的全排列.填空题

题目描述

今天,桐桐的老师布置了一道数学作业,要求列出所有从数字 1 到数字 n 的连续自然数的排列,要求所产生的任一数字序列中不允许出现重复的数字。因为排列数很多,桐桐害怕写漏了,所以她决定用计算机编程来解决。

输入格式

只有一个整数 n(1 ≤ n ≤ 9)。

输出格式

按字典序输出由 1 至 n 组成的所有不重复的数字序列,每行一个序列,每个数字之间有一个空格。

样例

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

解题思路

我们设想,我们要给一个数组 x[10] 填数,从 x[1] 开始,填到 x[n],条件是 x[1] 到 x[n] 是没有重复的数字的。每当填完 n 个数字就是找到了一个排列,就输出。

大的思路就是上面说的这样的,从细节来看其实需要考虑好几个问题。从 x[1] 填数填到 x[n],这是一个层层深入的问题,但是,到什么时候终止,这要控制好。大家看过电影《盗梦空间》没有,电影里面就是一个梦境套一个梦境的,梦里有梦,梦里再有梦....,但是,总要有一个时候你要控制你从某一层梦境中走出来,否则,人就陷入了困境,永远都出不来了。

第二个问题,就是这些排列要有顺序,是要按照字典序来排列的。

我们画了下面的这张图,这是一棵树。数根是 x[0] ,但是本题我们不用 x[0],我们从 x[1] 开始用,一直用到 x[n],每当填按 x[i] ,我们就要下探一层,给 x[i+1] 填数。这个过程,可以是一个递归过程。我们还可以通过打标记来记住某一个数字是否已经被用过,用过了就不能在下层的“梦境”里面重复使用。为了让梦境与梦境之间能够共享数据,这个标记数组应该是全局变量。

当我们试图给第 n+1 层(x[n+1])填数的时候,说明已经完成了从 x[1] 到 x[n] 的填数,这时候就可以输出了。

img

完善程序

#include<bits/stdc++.h>
using namespace std;
int x[10],n;
bool used[10];
void dfs(int l) // 给 x[l] 填数 
{
	if( 填空(1) ) // 已经填到第 n+1 层,说明了 x[1] 到 x[n] 都填好了; 
	{
		for(int i=1;i<=n;i++)
			printf("%d ",填空(2));
		printf("\n");
	}
	else
	{
		for(int i=1;填空(3);i++) // 枚举所有可填数字
		{
			if(填空(4)){ // 确保 i 是没有用过的 
				x[l] = i; // 给第 l 层数字填 i
				
				used[i] = 填空(5); // 在进入下一层“梦境”之前给 i 打上标记,下层的“梦境”不能再填 i 
				dfs( 填空(6) ); //通过递归函数进入下一层“梦境”,给 x 数组的下一层填数
				填空(7);
			}
		}
	}
}

int main()
{
	cin>>n;
	
	填空(8);

	return 0;
}

填空(1):{{ input(1) }}

填空(2):{{ input(2) }}

填空(3):{{ input(3) }}

填空(4):{{ input(4) }}

填空(5):{{ input(5) }}

填空(6):{{ input(6) }}

填空(7):{{ input(7) }}

填空(8):{{ input(8) }}