回溯:当把问题分成若干个步骤时,如果当前部骤没有合法选择,则函数将返回上一级递归调用,这种现象称为回溯,因此,递归枚举算法有常被称为回溯法;
n皇后问题: 思考:1。从64个格子选出一个子集使得任意一个格子不在同一行同一列同一对角线上,即子集枚举问题,64个格子的子集有2^64个,太大不够好
2。从64个格子里选出8个格子,即组合生成问题,有C8 64 =4*10^9 种方案,仍不够好
继而发现:恰每行每列格放置一个皇后,如果用c[x]表示第x行皇后的列,则只有8!=40320种排列
实现: 数组坐标化 同一列 x1=x2 同一主对角线 y1-x1=y2-x2 同一副对角线 y1+x1=y2+x2
用数组 储存各皇后 的 这三项参数值
~如果有多组数据,先预处理打表,防止重复计算超时
#include<cstdio> #include<cstring> using namespace std; int c[15],n,ans[15],k=0; int idx[5][40]; void dfs(int cur){ if(cur>=n){k++; return;} for(int i=0;i<n;i++){ if(!idx[0][i]&&!idx[1][cur+i]&&!idx[2][n+cur-i]) {idx[0][i]=idx[1][cur+i]=idx[2][n+cur-i]=1; dfs(cur+1); idx[0][i]=idx[1][cur+i]=idx[2][n+cur-i]=0; } } } int main(){ for(int i=1;i<11;i++){ n=i; k=0; dfs(0); ans[i]=k; } //freopen("ans.txt","w",stdout); while(scanf("%d",&n)!=EOF&&n){ printf("%d ",ans[n]); } }
素数环 uva 524
~事先素数打表
~奇偶剪枝
#include<cstdio> using namespace std; int a[20]={0},b[20],c[40]={0},n,ks=0;; void dfs(int cur){ if(cur>n&&c[b[n]+1]){ for(int i=1;i<=n;i++) if(i!=1)printf(" %d",b[i]); else printf("%d",b[i]); printf(" "); return ; } //奇偶剪枝 if(cur%2==1){ for(int i=3;i<=n;i+=2){ if(c[i+b[cur-1]]&&!a[i]){ a[i]=1; b[cur]=i; dfs(cur+1); a[i]=0; } } } else for(int i=2;i<=n;i+=2){ if(c[i+b[cur-1]]&&!a[i]){ a[i]=1; b[cur]=i; dfs(cur+1); a[i]=0; } } } int main(){ b[1]=1; c[2]=c[3]=c[5]=c[7]=c[11]=c[13]=c[17]=c[19]=c[23]=c[29]=c[31]=1;//素数打表 while(scanf("%d",&n)!=EOF){ if(ks)printf(" "); printf("Case %d: ",++ks); dfs(2); } return 0; }