再解决全排列问题前首先理解DFS深度搜索
假设有 3 个空位,从前往后填数字,每次填一个位置,填的数字不能和前面一样。
以一条边为例,
最开始的时候,三个空位都是空的:__ __ __
首先填写第一个空位,第一个空位可以填 1,填写后为:1 __ __
填好第一个空位,填第二个空位,第二个空位可以填 2,填写后为:1 2 __
填好第二个空位,填第三个空位,第三个空位可以填 3,填写后为: 1 2 3
这时候,空位填完,无法继续填数,所以这是一种方案,输出。
然后往后退一步,退到了状态:1 2 __ 。剩余第三个空位没有填数。第三个空位上除了填过的 3 ,没有其他数字可以填。
因此再往后退一步,退到了状态:1 __ __。第二个空位上除了填过的 2,还可以填 3。第二个空位上填写 3,填写后为:1 3 __
填好第二个空位,填第三个空位,第三个空位可以填 2,填写后为: 1 3 2
这时候,空位填完(x满足大于n的深度),无法继续填数,所以这是一种方案,输出。
我们先看看代码,看完后我再告诉大家技巧。好的,走起。
#include<iostream> using namespace std; const int N=10010;//定义常数 int path[N];//表示路径 int n;//输入几个数据 int st[N];//表示当前数字是否被使用 void dfs(int x) { if(x>n)//x==3不行,因为要填第三个数,必须大于 { for(int i=1;i<=n;i++)//输出用循环,从一开始一直到第三层 cout<<path[i]<<" "; printf("\n"); } else { for(int i=1;i<=n;i++)//横向排数 { if(!st[i])//如果没被使用 { path[x]=i; st[i]=1; dfs(x+1);//往下层走 st[i]=0;//走到底部,赋值为0,表示回到原本未被使用状态 } } } } int main() { cin>>n; dfs(1);//从第一层走起 return 0; }
好的看完后听我的技巧,总之一句话,理解递归千万不能想去模拟递归过程,记住递归的作用,远远比模拟过程重要。
在本题目中想让我们填数,此时递归的作用是往下递归一次,填下一位数,for循环是枚举当前状态下的另一种填数可能。好了,解决代码了,首先一次如果x>n表示填完就输出,没填完从一开始填入,第一次for枚举三种可能,往下没用过的数,填入,递归进下一位,在枚举可能情况,出来用完数记得归0,表示可用,知道递归到x>n表示结束了到底了。