Checker Challenge

  经典的八皇后问题。思路很明确,搜索,每次决策一行中的一个皇后,因此只需对列,正逆对角线进行标识即可。可这样做最后一个案例会超时。其实我们还没有完全挖掘出题目中的隐含信息,注意到解是具有对称性的,所以我们只需搜索一半,当n为奇数时,第一行的最中间的一个皇后单独搜。

//diag(a[i][j])=i-j+n-1 rdiag(a[i][j])=i+j; #include<iostream> #include<string.h> #include<fstream> using namespace std; #define N 13 bool line[N],diag[2*N],rdiag[2*N]; int ans[3][N],cnt,tmp[N]; int n; void dfs(int k){ if(k==n){ if(cnt<3){ memcpy(ans[cnt],tmp,sizeof(tmp)); } cnt++; } else{ int i; for(i=0;i< (k?n:n/2) ; i++){ if( !line[i] && !diag[k-i+n-1] && !rdiag[i+k] ){ line[i]=diag[k-i+n-1]=rdiag[i+k]=true; tmp[k]=i; dfs(k+1); line[i]=diag[k-i+n-1]=rdiag[i+k]=false; } } } } int main(){ ifstream cin("checker.in"); ofstream cout("checker.out"); cin>>n; memset(line,0,sizeof(line)); memset(diag,0,sizeof(diag)); memset(rdiag,0,sizeof(rdiag)); cnt=0; dfs(0); int t=cnt; if(n&1){//单独搜 tmp[0]=n/2; line[n/2]=diag[n-1-n/2]=rdiag[n/2]=true; dfs(1); line[n/2]=diag[n-1-n/2]=rdiag[n/2]=false; } int tot=t*2+(cnt-t); //不足3个时从尾向前copy 3-cnt个补足3个 if(cnt<3){ int i,j; for(i=tot/2-1;i>tot/2-4+cnt;i--){ for(j=0;j<n;j++)ans[tot-i-1][j]=n-ans[i][j]-1; } } int i,j; for(i=0;i<3;i++){ for(j=0;j<n-1;j++) { cout<<ans[i][j]+1<<' '; } cout<<ans[i][j]+1<<endl; } cout<<tot<<endl; return 0; }

 

其实这题还有位运算的版本,本质没变,因此时间复杂度是一样的,但实际效率却高得多,可见计算机位运算是很快的!

我也是参考了网上写的。

//异或运算的本质和1异或取反,和0异或不变!!! //n位的数org取反用full=2^n-1;ans=full^org; #include <iostream> #include<cstdio> using namespace std; #define N 15 int n,ans[3][N],cnt; long long full;//full=2^n-1 long long column[N],ldiag[N],rdiag[N];//列,副对角线,主对角线的禁位 void getAns(){ int i; for(i=0;i<n;i++){ long long pos=column[i]^column[i+1];// int loc=-1;//计算皇后摆放位置 while(pos){ pos>>=1; loc++; } ans[cnt][i]=loc; } } void dfs(int k){ if(k==n){ if(cnt<3)getAns(); cnt++; } else{ long long allow=full^ ( column[k] | ldiag[k] | rdiag[k] ); //获取允许摆放的位置 while(allow){ //修改下一行禁位 long long pos=allow & (-allow ); column[k+1]=column[k] | pos; ldiag[k+1]=( (ldiag[k] | pos)<<1 ) & full; rdiag[k+1]=( (rdiag[k] | pos)>>1 ); dfs(k+1); allow-=pos;//去掉已搜索过的位置 } } } int main(){ freopen("checker.in","r",stdin); freopen("checker.out","w",stdout); cin>>n; cnt=0; full=(1<<n)-1;//低n位全置1 column[0]=ldiag[0]=rdiag[0]=0;//初使无禁位 dfs(0); int i,j; for(i=0;i<3;i++){ for(j=0;j<n-1;j++) cout<<ans[i][j]+1<<' '; cout<<ans[i][j]+1<<endl; } cout<<cnt<<endl; return 0; }

 

原理参考:http://www.matrix67.com/blog/archives/266

代码参考:找不到原文了,不好意思!

 

 

你可能感兴趣的:(Checker Challenge)