题目链接: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 }
完。