文章目录
n-皇后问题
参考@竹林正在青
DFS 看 搜索顺序
递归步骤:1.边界 2.递归 3.恢复现场
第一种搜索方式(按行搜索)
/*
第一种搜索顺序
定义纵坐标为y轴,横坐标为x轴,u是每一层的状态,i是枚举每一列的状态,那么y:u, x:i;
正对角线y = x+b -> b = y-x+n; 反对角线是 y = -x+b -> b = x+y;那么应该是dg[n+u-i],udg[u+i].
*/
#include <iostream>
using namespace std;
const int N = 20; // 对角线的数量是n*2,所以要开20
int n;
char g[N][N];
bool col[N],row[N],dg[N],udg[N];//col是行,row是列,dg是正对角线,udg是反对角线
void dfs(int u)
{
// 1.边界 2.递归 3.恢复现场
if(u == n)
{
for(int i = 0; i < n; i++) cout << g[i] << endl;
cout << endl;
return ;
}
// y:u, x:i
for(int i=0;i<n;i++)
if(!col[i] && !dg[u-i+n] && !udg[u+i])
{
g[u][i]='Q';
col[i]=dg[u-i+n]=udg[u+i]=true;
dfs(u+1);
g[u][i]='.';
col[i]=dg[u-i+n]=udg[u+i]=false;
}
}
int main()
{
cin >> n;
for (int i = 0; i < n; i ++ )
for (int j = 0; j < n; j ++ )
g[i][j] = '.';
dfs(0); // 按行枚举
return 0;
}
第二种搜索方式(按每一格搜索)
/*
第一种搜索顺序
定义纵坐标为y轴,横坐标为x轴,u是每一层的状态,i是枚举每一列的状态,那么y:u, x:i;
正对角线y = x+b -> b = y-x+n; 反对角线是 y = -x+b -> b = x+y;那么应该是dg[n+u-i],udg[u+i].
*/
#include <iostream>
using namespace std;
const int N = 20; // 对角线的数量是n*2,所以要开20
int n;
char g[N][N];
bool col[N],row[N],dg[N],udg[N];//col是行,row是列,dg是正对角线,udg是反对角线
void dfs(int u)
{
// 1.边界 2.递归 3.恢复现场
if(u == n)
{
for(int i = 0; i < n; i++) cout << g[i] << endl;
cout << endl;
return ;
}
// y:u, x:i
for(int i=0;i<n;i++)
if(!col[i] && !dg[u-i+n] && !udg[u+i])
{
g[u][i]='Q';
col[i]=dg[u-i+n]=udg[u+i]=true;
dfs(u+1);
g[u][i]='.';
col[i]=dg[u-i+n]=udg[u+i]=false;
}
}
void dfs2(int x,int y,int s)
{
if(y==n) y=0,x++;
if(x==n)
{
if(s==n)
{
for(int i=0;i<n;i++) cout<<g[i]<<endl;
cout<<endl;
}
return ;
}
//不放
dfs2(x,y+1,s);
//放
if(!col[x] && !row[y] && !dg[y-x+n] && !udg[y+x])
{
g[x][y]='Q';
col[x]=row[y]=dg[y-x+n]=udg[y+x]=true;
dfs2(x,y+1,s+1);
g[x][y]='.';
col[x]=row[y]=dg[y-x+n]=udg[y+x]=false;
}
}
int main()
{
cin >> n;
for (int i = 0; i < n; i ++ )
for (int j = 0; j < n; j ++ )
g[i][j] = '.';
//dfs(0); // 按行枚举
dfs2(0,0,0); //按每一格枚举
return 0;
}
N 皇后问题
注意此题坐标系
#include <iostream>
#include <vector>
#include <cstring>
using namespace std;
typedef pair<int,int> PII;
const int N = 1000 * 2;
bool col[N],row[N],dg[N],udg[N];
int main()
{
int t;
cin >> t;
while(t--)
{
memset(col,0,sizeof col);
memset(row,0,sizeof row);
memset(dg,0,sizeof dg);
memset(udg,0,sizeof udg);
int x,cnt; // x为行号,i为列号,从1开始
vector<PII> queen;
cin >> cnt;
for(int i=1;i<=cnt;i++)
{
cin >>x;
queen.push_back({x,i});
}
int n =cnt;
bool flag=1;
for(int i=0;i<queen.size();i++) // 枚举每个皇后
{
int x=queen[i].first,y=queen[i].second;
//cout<<x<<" "<<y<<endl;
if(!col[x] && !row[y] && !dg[y-x+n] && !udg[y+x])
{
col[x] = row[y] = dg[y-x+n] = udg[y+x] = true;
}
else
{
flag=0;
break;
}
}
if(flag) puts("YES");
else puts("NO");
}
return 0;
}
P1219 [USACO1.5]八皇后 Checker Challenge
#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
const int N = 30; // 对角线的数量是2倍!! 还真是!
int n;
char g[N][N];
bool col[N],row[N],dg[N],udg[N];
int res;
vector<vector<int> > nums;
vector<int> num;
void dfs2(int u)
{
if(u==n){
res++;
nums.push_back(num);
return ;
}
// u : y , i : x
for(int i=0;i<n;i++)
{
if(!col[i] && !dg[u-i+n] && !udg[u+i] && g[u][i]!='.' )
{
col[i]=dg[u-i+n]=udg[u+i]=true;
num.push_back(i+1);
dfs2(u+1);
col[i]=dg[u-i+n]=udg[u+i]=false;
num.pop_back();
}
}
}
int main()
{
cin>>n;
//dfs(0,0,0); // 按每格枚举
dfs2(0); // 按每行枚举
for(int i=0;i<3;i++){
for(int j=0;j<nums[i].size();j++)
cout<<nums[i][j]<<" ";
cout<<endl;
}
cout<<res<<endl;
return 0;
}
P2105 K皇后
观察到数据范围
如果扫描整个棋盘,时间复杂度是O(nm) = 4 × 1 0 8 4×10^8 4×108,是会超时的。观察到K只有500
换种思路:先枚举每行,再枚举每个皇后,时间复杂度O(nk) < 1 0 8 10^8 108,可以通过
#include <iostream>
#include <vector>
#include <cstring>
using namespace std;
typedef pair<int,int> PII;
const int N = 20010;
int n,m,k;
vector<PII> queen;
bool row[N];
bool st[N]; // 每一行格子的状态
int main()
{
cin >> n >> m >> k;
for(int i=0;i<k;i++)
{
int x,y;
cin >> x >> y;
row[x] = true;
queen.push_back({x,y});
}
int res=0;
for(int i=1;i<=n;i++) // 枚举每一行
{
if(row[i]) continue;
else
{
int sum = m;
memset(st,0,sizeof st);
for(int j=0;j<k;j++) // 枚举k个皇后
{
int x= queen[j].first,y=queen[j].second;
// 竖线
if(st[y] == false)
{
st[y] = true;
sum --;
}
// 正对角线,反对角线
int k1=y-x+i, k2 = y+x - i;
if(k1 >=1 && k1<=m && !st[k1]) // 符合条件
{
st[k1] = true;
sum --;
}
if(k2 >=1 && k2<=m && !st[k2])
{
st[k2] = true;
sum --;
}
}
res += sum;
}
}
cout<<res;
return 0;
}