洛谷P1219八皇後(遞歸搜索dfs+回溯更新)
阿新 • • 發佈:2018-10-05
cstring cout std 搜索 amp name span 數組 string
題目鏈接:https://www.luogu.org/problemnew/show/P1219
這題就是搜索遞歸dfs+回溯更新,,有多個標記數組。
難點在於:怎樣標記(列標記還好,對角線標記麻煩!),是關鍵。
註意怎樣標記需要必須想出這個規律:主對角線相減為定值(相減可能為負數,所以統一加n不影響結果),次對角線相加為定值。到這題目就做出來了。
題目跟全排列比較像,屬於一類題。
1 #include <iostream> 2 #include <string> 3 #include <algorithm> 4 #include <cstdio> 5#include <cstring> 6 using namespace std; 7 typedef long long ll; 8 typedef unsigned long long ull; 9 const int maxn=1e3+5; 10 const int inf=1e9; 11 int ans[maxn]; 12 int vis[3][maxn];//vis[0][maxn]存列,vis[1][maxn]存左下到右上對角線,vis[2][maxn]存右下到左上對角線 13 int n,cnt; 14 15 void so(int i)//i第幾行 16 { 17 if(i>n)//遞歸出口,序列已經排好 18 { 19 cnt++; 20 if(cnt<=3) 21 { 22 for(int k=1;k<=n-1;k++) cout<<ans[k]<<‘ ‘; 23 cout<<ans[n]<<endl; 24 } 25 return; 26 } 27 28 for(int j=1;j<=n;j++) 29 { 30 if(vis[0][j]==0 && vis[1][i-j+n]==0 && vis[2][i+j]==0) 31 { 32 vis[0][j]=1; 33 vis[1][i-j+n]=1; 34 vis[2][i+j]=1; 35 36 ans[i]=j; 37 so(i+1); 38 39 vis[0][j]=0; 40 vis[1][i-j+n]=0; 41 vis[2][i+j]=0; 42 } 43 } 44 } 45 46 47 int main() 48 { 49 ios::sync_with_stdio(false); cin.tie(0); 50 51 cin>>n; 52 53 so(1); 54 55 cout<<cnt<<endl; 56 57 return 0; 58 }
再附個全排列代碼
全排列很簡單,就是從小到大所有情況都來一遍,以3為例跟一遍代碼就明白
1 #include <iostream> 2 #include <string> 3 #include <algorithm> 4 #include <cstdio> 5 #include <cstring> 6 using namespace std; 7 typedef long long ll; 8 typedef unsigned long long ull; 9 const int maxn=1e3+5; 10 const int inf=1e9; 11 int ans[maxn]; 12 int vis[maxn];//標記數組 13 int n,cnt; 14 15 void so(int k) 16 { 17 if(k>n) 18 { 19 for(int i=1;i<=n-1;i++) cout<<ans[i]<<‘ ‘; 20 cout<<ans[n]<<endl; 21 return; 22 } 23 24 for(int i=1;i<=n;i++)//i從1到n,只要有小的就用上,所以說一定是字典序從小到大的排列,每個排列都試一遍就成了全排列 25 { 26 if(vis[i]==0) 27 { 28 vis[i]=1; 29 30 ans[k]=i; 31 so(k+1); 32 33 vis[i]=0; 34 } 35 } 36 } 37 38 39 int main() 40 { 41 ios::sync_with_stdio(false); cin.tie(0); 42 43 cin>>n; 44 45 so(1); 46 47 return 0; 48 }
完。
洛谷P1219八皇後(遞歸搜索dfs+回溯更新)