由上面的分析和递推公式就很容易写出代码了:
#include<iostream> using namespace std; void Full_permutation(int* A,int beg,int end) { if(beg == end) { for(int i=0;i<=end;++i) cout<<A[i]<<' '; cout<<endl; return ; } for(int i=beg;i <= end; ++i)//A[1]有n种选择,需要n次循环 { swap(A[beg],A[i]); //选择beg的值 Full_permutation(A,beg+1,end);//求解n-1子问题 swap(A[beg],A[i]); } } int main() { int A[8]={0,1,2,3,4,5,6,7}; Full_permutation(A,0,7); return 0; }扩展:由时间复杂度为(n!),我们容易联想到n皇后问题,最经典的八皇后问题:在8×8的国际象棋上摆放八个皇后,使其不能相互攻击,即任意两个皇后不得处在同一行、同一列或者同一对角斜线上。我们可以这么分析,先从行入手,第1个皇后可以在第1行上选择8个位置,第2个皇后可以在第2行选择7个位置(只要不和第1个皇后同列),第3个皇后可以在第1行上选择6个位置(只要不和第1,2个皇后同列).如果不考虑对角线的攻击方向,那么n皇后问题可以有n!个解,和上面的全排列一样.同样,我们可以先考虑行和列的n!种所有情况,然后排除对角线冲突的情况,进而缩小范围,就可以找出8皇后的解.基于这个想法,八皇后问题并不难.现在,我们还剩下最后一个问题?用什么数据结构保存皇后的二维坐标,其实很容易,用(i,A[i])就可以保存皇后的位置,即一个数组,索引i表示行,A[i]表示列.定义一个A[8]就可以表示八皇后.
由这个思路,代码:
#include<iostream> using namespace std; bool isLegalQueens(int* A,int end) { for(int i=0; i<=end; ++i) { for(int j=i+1; j <=end; ++j) { if( A[j]-A[i] == j-i || A[j]-A[i] == i-j )//两点的斜率如果为1或-1,则为不合法 return false; } } return true; } void Full_permutation(int* A,int beg,int end) { if(beg == end) { if(isLegalQueens(A,end)) { for(int i=0;i<=end;++i) cout<<A[i]<<' '; cout<<endl; } return ; } for(int i=beg;i <= end; ++i)//A[1]有n种选择,需要n次循环 { swap(A[beg],A[i]);//选择beg的值 Full_permutation(A,beg+1,end);//求解n-1子问题 swap(A[beg],A[i]); } } int main() { int A[8]={0,1,2,3,4,5,6,7}; Full_permutation(A,0,7); return 0; }
实训:http://acm.hdu.edu.cn/showproblem.php?pid=2804
4、一边有 n 个圈的正三角形棋盘,
(1)当 n=3k+1 时,最多可放置(2k+1)个皇后,k=0,1,2,3,……
(2)当 n=3k+2 时,最多可放置(2k+1)个皇后,k=0,1,2,3,……
(3)当 n=3k+3 时,最多可放置(2k+2)个皇后,k=0,1,2,3,……
具体的证明过程见这篇论文:三角形八皇后问题证明
知道上面的结论之后,代码会简洁到难以置信!
#include<iostream> using namespace std; typedef long long LLong; int main() { LLong n; while(cin>>n && n!=0) { if( n%3== 0) cout<<2*(n/3)<<endl; else cout<<2*(n/3)+1<<endl; } return 0; }