給定一個n*n的棋盤,棋盤中有一些位置不能放皇后。
現在要向棋盤中放入n個黑皇后和n個白皇后,使任意的兩個黑皇后都不在同一行、同一列或同一條對角線上,任意的兩個白皇后都不在同一行、同一列或同一條對角線上。
問總共有多少種放法?
輸入的第一行為一個整數n,表示棋盤的大小。
接下來n行,每行n個0或1的整數,如果一個整數為1,表示對應的位置可以放皇后,如果一個整數為0,表示對應的位置不可以放皇后。
n小于等于8。
輸出一個整數,表示總共有多少種放法。
4 1111 1111 1111 1111 4 1011 1111 1111 1111 樣例輸出 2 0
探討2n皇后問題之前,先看看N皇后問題 用vis[3][] 標記已經訪問過的縱,和兩個對角線。這樣復雜度就可以大大減低o(1)的時間內可以判定是否可行。
對于縱排是否可以訪問只要記錄那一縱的橫坐標即可;對角線是直線,我們記錄他的截距即可。
說了這么多,為什么我沒提到橫排的問題,這個自己體會代碼吧,懶得打字了。
#include<stdio.h>#include<string.h>#define MAX_N 8bool map[MAX_N][MAX_N];bool vis[3][MAX_N*2];int N,ans;void dfs_1(int cnt){ if(cnt==N){ans++;return ;} for(int i=0;i<N;i++){ if(vis[0][i]||vis[1][i+cnt]||vis[2][N-cnt+i]) continue; vis[0][i]=vis[1][i+cnt]=vis[2][N-cnt+i]=true; dfs_1(cnt+1); vis[0][i]=vis[1][i+cnt]=vis[2][N-cnt+i]=false; }}int main(){ while(~scanf("%d",&N)){ for(int j=0;j<N;j++) for(int k=0;k<N;k++) scanf("%1d",&map[k][j]); ans=0; dfs_1(0); 在上面基礎上dfs再走一遍就解決2n皇后問題了 //我把bool型的map寫成char,因為這個WA了兩次,,,我也不知道原因,理論上是沒問題的,不知道是oj的問題還是數據的問題#include<stdio.h>#include<string.h>#define MAX_N 20char map[MAX_N][MAX_N];bool vis[3][MAX_N*2];bool vis_0[3][MAX_N*2];bool used[MAX_N][MAX_N];int N,ans;void dfs_0(int cnt){ if(cnt==N){ans++;return ;} for(int i=0;i<N;i++){ if(vis_0[0][i]||vis_0[1][i+cnt]||vis_0[2][N-cnt+i]||used[cnt][i]||map[cnt][i]=='0') continue; vis_0[0][i]=vis_0[1][i+cnt]=vis_0[2][N-cnt+i]=true; dfs_0(cnt+1); vis_0[0][i]=vis_0[1][i+cnt]=vis_0[2][N-cnt+i]=false; }}void dfs_1(int cnt){ if(cnt==N){ dfs_0(0); return ;} for(int i=0;i<N;i++){ if(vis[0][i]||vis[1][i+cnt]||vis[2][N-cnt+i]||map[cnt][i]=='0') continue; used[cnt][i]=vis[0][i]=vis[1][i+cnt]=vis[2][N-cnt+i]=true; dfs_1(cnt+1); used[cnt][i]=vis[0][i]=vis[1][i+cnt]=vis[2][N-cnt+i]=false; }}int main(){ while(~scanf("%d",&N)){ for(int j=0;j<N;j++) scanf("%s",map[j]); memset(vis,0,sizeof(vis)); memset(vis_0,0,sizeof(vis_0)); memset(used,0,sizeof(used)); ans=0; dfs_1(0); printf("%d/n",ans); } return 0;}新聞熱點
疑難解答