/*
回溯法:
排列生成和子集枚举的两种方法:1递归,2遍历
遍历:优点:简单,缺点:增大枚举量,检验所有解
回溯法:含义 :递归时,将生成+检查过程结合
适合:问题分成步骤,步骤采用不太多选择
回溯算法=递归枚举算法:分成若干步骤递归,若某一步无解,返回上一级调用,称为回溯。
八皇后问题:
在棋盘上放置8个皇后,使得她们互不攻击,此时每个皇后的攻击范围为同行同列和同对角线,要求找出所有解。
一个可行解
Q
Q
Q
Q
Q
Q
Q
Q
思路:
1 不知道剪枝条件是什么。
2 不知道怎样确认是否是8个
*/
/*
关键:
1 由于题目条件限制,每一行,每一列只有一个,将问题简化为:对每一行,选择不重复的列。
剪枝条件:不在同一行和同一列,同一对角线。
2 排列数共8!=40320个
3 我们利用逐行放置来限定:行不同,通过列号不同来限定:列不同,主对角线:行号与列号相减值不同来限定主对角线不同,副对角线:行号与列号相加值不同限定
副对角线不同。if(iArr[pos] == iArr[j] || pos - iArr[pos] == j - iArr[j] || pos + iArr[pos] == j + iArr[j])//剪枝条件
4 该题仍然抽象为:用递归来求不重复的全排列+剪枝条件
5 if(pos == n)//递归出口是,位置已经到达顶点
{
cnt++;
}
6 if(isFind)//如果合法,继续递归
{
eightQueen(n,pos+1,iArr);
}
7 八皇后方法2:
for(int i = 0 ; i < n;i++)//这里的i表示列,pos表示行
8 if(!vis[0][i] && !vis[1][pos+i] && !vis[2][pos-i+n])//pos+i:表示行+列,pos-i+n:表示行-列+n,放置行减列可能为负,所以加n
9 path[pos] = i;//列
vis[0][i] = vis[1][pos+i] = vis[2][pos-i+n] = 1;//置访问标记已经访问过
search(n,pos+1);
vis[0][i] = vis[1][pos+i] = vis[2][pos-i+n] = 0;//回溯法,要重新置访问标记
注意回溯法使用辅助的全局标记变量,记得要恢复原状
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXSIZE 1024
int cnt;
void eightQueen(int n,int pos,int* iArr)
{
if(pos == n)//递归出口是,位置已经到达顶点
{
cnt++;
}
else
{
for(int i = 0 ; i < n ; i++)
{
iArr[pos] = i;//尝试把第pos行皇后放在第i列上
bool isFind = true;
for(int j = 0 ; j < pos ; j++)
{
if(iArr[pos] == iArr[j] || pos - iArr[pos] == j - iArr[j] || pos + iArr[pos] == j + iArr[j])//剪枝条件
{
isFind = false;
break;
}
}
if(isFind)//如果合法,继续递归
{
eightQueen(n,pos+1,iArr);
}
}
}
}
//八皇后问题解法2:采用二维数组标记:列,主对角线,副对角线
int vis[2][MAXSIZE];//原来为0,表示没有访问过,一旦已经访问过置为1
int path[MAXSIZE];
int cnt1;
void search(int n,int pos)
{
if(pos == n)//如果达到递归程序出口,直接退出
{
cnt1++;
}
else
{
for(int i = 0 ; i < n;i++)//这里的i表示列,pos表示行
{
//if(!vis[0][i] || )//如果为0表示还没有访问过,这是可以放置皇后
if(!vis[0][i] && !vis[1][pos+i] && !vis[2][pos-i+n])//pos+i:表示行+列,pos-i+n:表示行-列+n,放置行减列可能为负,所以加n
{
path[pos] = i;//列
vis[0][i] = vis[1][pos+i] = vis[2][pos-i+n] = 1;//置访问标记已经访问过
search(n,pos+1);
vis[0][i] = vis[1][pos+i] = vis[2][pos-i+n] = 0;//回溯法,要重新置访问标记
}
}
}
}
int main(int argc,char* argv[])
{
int n;
while(EOF != scanf("%d",&n))
{
memset(vis,0,sizeof(vis));
cnt = 0;
cnt1 = 0;
int pos = 0,pos1 = 0;
int iArr[MAXSIZE];
eightQueen(n,pos,iArr);
search(n,pos1);
printf("%d\n",cnt);
printf("%d\n",cnt1);
}
system("pause");
return 0;
}
算法竞赛入门经典:第七章 暴力求解法 7.11回溯法
最新推荐文章于 2023-12-15 18:43:09 发布