小Q是班长。在校运动会上,小Q班要进行队列表演。小Q要选出2*N名同窗编队,每人都被编上一个号,每个从1到N的天然数都被某2名同窗佩戴,如今要求将他们排成一列,使两个编号为1的同窗中间刚好夹1名同窗,两个编号为2的同窗中间刚好夹2名同窗,……,两个编号为N的同窗中间刚好夹N名同窗,小Q但愿知道这样的排法可否实现。c++
输入文件仅包括一行,即要处理的N。N<=13优化
输出有多少种排列顺序.spa
3code
2blog
先理解一下题目,题目中所述,每个从1到N的天然数都被某2名同窗佩戴,说明共有2N名同窗,两个编号为N的同窗中间刚好夹N名同窗,就能够获得一个排列(以n==3为例):队列
而后,就能够用DFS搜索了。图片
#include<bits/stdc++.h> using namespace std; int n,ans=0; int flag[100]={0}; void dfs(int dep){ if(dep>n){ ans++; return ; } for(int i=1;i<=2*n-dep-1;i++){ if(!flag[i]&&!flag[i+dep+1]){//考虑当前位置有无其余数,和它的间隔有没有其余数 flag[i]=flag[i+dep+1]=1; dfs(dep+1); flag[i]=flag[i+dep+1]=0; } } } int main(){ cin >> n; dfs(1); cout << ans; return 0; }
可是,能够发现,当程序运行12或13时,耗时很长,那么就能够想到剪枝优化。ip
if(n%4==1||n%4==2){ return ; }
如今,就能够证实一下这个剪枝的获得。
设问题的一个解为a1+a2···+an,a1表示1。
那么能够获得a1+a2+…+an+(a1+1+1)+(a2+2+1)+…+(an+n+1),最后解得4(a1+a2+…+an)=n(3n-1),因此n%41或n%42无解。ci
#include<bits/stdc++.h> using namespace std; int n,ans=0; int flag[100]={0}; void dfs(int dep){ if(n%4==1||n%4==2){ return ; } if(dep>n){ ans++; return ; } for(int i=1;i<=2*n-dep-1;i++){ if(!flag[i]&&!flag[i+dep+1]){ flag[i]=flag[i+dep+1]=1; dfs(dep+1); flag[i]=flag[i+dep+1]=0; } } } int main(){ cin >> n; dfs(1); cout << ans; return 0; }