算法设计(一) : 搜索算法实现八皇后问题

115 篇文章 3 订阅

写在开头:实验结果截图8皇后太多截不完,用4皇后代替了,只需将n->8就行

图解算法过程:

在这里插入图片描述
下面分析中的 ( x , y ) (x,y) (x,y)相当于上面的 ( u , i ) (u,i) (u,i)
反对角线 y = x + b y=x+b y=x+b, 截距 b = y − x b=y−x b=yx,因为我们要把 b b b 当做数组下标来用,显然 b b b 不能是的,所以我们加上 n (实际上 + n + 4 +n+4 +n+4, + 2 n +2n +2n都行),来保证是结果是正的,即 y − x + n y - x + n yx+n
而对角线 y = − x + b y=−x+b y=x+b 截距是 b = y + x b=y+x b=y+x,这里截距一定是的,所以不需要加偏移量
核心目的:找一些合法的下标来表示dgudg是否被标记过,所以如果你愿意,你取 udg[n−u+i] 也可以,只要所有(u,i)对可以映射过去就行

算法一:DFS 按行枚举,时间复杂度O(n!)

const int N=25;
int n;
char g[N][N];
bool dg[N],udg[N],col[N];//对角线 dg[u+i],反对角线udg[n−u+i]中的下标 u+i和 n−u+i 表示的是截距
int k=1;
void dfs(int u)
{
	if(u==n)
	{
		cout<<n<<"皇后的第"<<k++<<"种方案:"<<endl;
		for(int i=0;i<n;i++)
				cout<<g[i]<<endl;
		cout<<endl;
		return; 
	}
	for(int i=0;i<n;i++)
	{
		if(!col[i]&&!dg[u+i]&&!udg[n-u+i])
		{
			g[u][i]='Q';
			col[i]=dg[u+i]=udg[n-u+i]=true;//标记 
			dfs(u+1);
			col[i]=dg[u+i]=udg[n-u+i]=false;//还原现场
			g[u][i]='.'; 
		}
	}
}
void solve()
{
	cin>>n;
	for(int i=0;i<n;i++)
		for(int j=0;j<n;j++)
			g[i][j]='.';
	dfs(0);
}

运行结果截图:

在这里插入图片描述
在这里插入图片描述

算法二:DFS按每个元素枚举 时间复杂度 O ( 2 n 2 ) O(2^{n^2}) O(2n2),每个位置都有两种情况,总共有 n 2 n^2 n2 个位置

const int N=25;
int n;
char g[N][N];
bool dg[N],udg[N],col[N],row[N];
int k=1;
void dfs(int x,int y,int s)
{
	if(y==n)y=0,x++;
	if(x==n)
	{
		if(s==n)
		{
			cout<<n<<"皇后的第"<<k++<<"种方案:"<<endl;
			for(int i=0;i<n;i++)
				cout<<g[i]<<endl;
			cout<<endl;
		}
		return;
	}
	if(!row[x]&&!col[y]&&!dg[x+y]&&!udg[x-y+n])//选 
	{
		g[x][y]='Q';
		row[x]=col[y]=dg[x+y]=udg[x-y+n]=true;
		dfs(x,y+1,s+1);
		row[x]=col[y]=dg[x+y]=udg[x-y+n]=false;
		g[x][y]='.';
	}
	//不选
	dfs(x,y+1,s); 
}
void solve()
{
	cin>>n;
	for(int i=0;i<n;i++)
		for(int j=0;j<n;j++)
			g[i][j]='.';
	dfs(0,0,0);
}

运行结果截图

在这里插入图片描述

在这里插入图片描述

算法三:二进制对空间进行优化

int lowbit(int x){return x&-x;}//最低位1及其后面的0构成的数值
const int N=25;
int n;
vector<string>g;
vector<vector<string>>res;
int cnt=1;
void dfs(int a,int b,int c,int k)
{
	if(k==n)
	{
		res.push_back(g);
		return;
	}
	for(int i=~(a|b|c)&((1<<n)-1);i;i-=lowbit(i))
	{
		int p=lowbit(i);
		g[k][log2(p)]='Q';//计算第几位是1,用对数函数log2十分方便
		dfs((a|p)<<1,(b|p)>>1,c|p,k+1);
		g[k][log2(p)]='.';
	}
}
void solve()
{
	cin>>n;
	vector<string>board(n,string(n,'.'));
	g=board;
	dfs(0,0,0,0);
	for(int i=0;i<res.size();i++)
	{
		cout<<n<<"皇后的第"<<cnt++<<"种方案:"<<endl;
		for(int j=0;j<res[i].size();j++)
		{
			cout<<res[i][j]<<endl;
		}
		cout<<endl;
	}
}

运行结果截图

在这里插入图片描述

在这里插入图片描述

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

leimingzeOuO

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值