回溯算法————n皇后、素数串

回溯就是算法是搜索算法中一种控制策略,是一个逐个试探的过程。在试探的过程中,如果遇到错误的选择,就会回到上一步继续选择下一种走法,一步一步的进行直到找到解或者证明无解为止。

如下是一个经典回溯问题n皇后的解答树:

下面就从n皇后说起:


【问题描述】

在n×n的国际象棋盘上,放置n个皇后,使任何一个皇后都不能吃掉另一个,需满足的条件是:同一行、同一列、同一对角线上只能有一个皇后。求所有满足要求的放置方案。4皇后的放置方案如下:

【输入】一个正整数n。

【输出】每行代表一种放置方案:第i行的第一个数是i,表示第i种方案,后面一个冒号,然后是用空格隔开的n个数,其中第i个数x[i]表示第i行上的皇后放在第x[i]列;最后一行:一个整数,表示方案总数。

【样例输入】

4

【样例输出】

1:2 4 1 3

2:3 1 4 2

2

这个题目简直是太经典了,一提到回溯第一个想到的就是它。这个题非常的通俗易懂,就是在一个n*n的棋盘上满足条件地放置n个皇后,每种组合搜一遍就好了。在搜的过程中判断下一步的某种方向是否可以走,如果可以的话就进入下一层,如果不符合要求就搜下一个方向,搜完这一层的所有方向以后就回到上一层,继续搜上一层的下一个方向。

不知道大家看懂了没有,如果没看懂,看代码就懂了。。

上代码:

#include<iostream>
#include<cstdio>

using namespace std;

int n;
int sum=0;//解法存放个数
int a[100000];//存放皇后位置数据
bool b[1000000]={0},c[1000000]={0},d[10000000]={0};//b存储y方向,c、d存储对角线

void print()
{
	sum++;
	cout<<sum<<‘:‘;
	for(int i=1;i<=n;i++)
	{
		cout<<a[i]<<‘ ‘;
	}
	cout<<endl;
}

int search(int x)
{
	for(int j=1;j<=n;j++)//遍历本层中每种方向
	{
		if((!b[j])&&(!c[x+j])&&(!d[x-j+n-1]))//如果满足条件
		{
			a[x]=j;//存入皇后数据
			b[j]=1;//占领y轴
			c[x+j]=1;//占领对角线
			d[x-j+n-1]=1;//占领对角线
			if(x==n)
			{
				print();//如果有完整解,输出
			}
			else
			{
				search(x+1);//如果没有继续找下一行
			}
			b[j]=0;//找完之后取消占领
			c[x+j]=0;
			d[x-j+n-1]=0;
		}
	}
}

int main()
{
	cin>>n;
	search(1);//从第一个开始找
	cout<<sum;
}

  把思想带到代码里应该就看懂了吧。

回溯就是这样一层一层的找,找完本层返回上一层继续找,直到找到正确解为止。

继续再看一道题:

3、素数链

设计程序将1。。。n排成一排,使任意两个相邻的数的和为素数。第1个和最后一个的和也为素数.输出一种方案即可。

输入:

n (n<=100)

输出:

1到n的一个序列,中间用一个空格隔开。第一个数为1。

如果无解输出-1。

样例输入:

10

样例输出:

1  2  3  4  7  6  5  8  9  10

这道题和刚才那道n皇后的思路是一样的,遍历所有可能,在遍历的过程中判断,如果可以就继续搜下一层。

代码如下:

#include<cstdio>
#include<iostream>

const int maxx=1000;

using namespace std;

int n;
int numguo[maxx]={0};
bool guo[maxx]={0},pguo=0;
int c=0;

int sushu(int x)//验证素数的函数
{
//关于判断素数的题很早就做过,这里我就不解释了
	int i=2;
	while(i<x)
	{
		if(x%i==0)
		return 0;//如果不是直接跳出返回0
		i++;
	}
	return 1;//如果是的话返回1
}

int panduan()
{
	int t;
	for(int i=1;i<n;i++)//判断是否达到要求
	{
		if(!sushu(numguo[i]+numguo[i+1]))//这里我直接放到函数里去验证
		{
			return 0;//如果不是素数就直接跳出返回0
		}
	}
	if(!sushu(numguo[n]+numguo[1])) return 0;//注意别忘了最后一个和第一个数字的和是否为素数
	return 1;//正确的话返回1
}

int print()
{
	c++;//可能方法+1
	for(int i=1;i<=n;i++){
		cout<<numguo[i]<<‘ ‘;
	}
	cout<<endl;
}

int search(int x)
{
	for(int i=1;i<=n;i++)//搜索本层中每种可能
	{
		if(!guo[i])
		{
			guo[i]=1;//占领
			numguo[x]=i;//标记
			if(x==n)//如果达到数量要求
			{

				if(panduan())//如果符合要求
				{
					if(!pguo)//如果没输出过
					{
						pguo=1;//输出过
						print();//输出
						return 0;//搜到就直接跳出
					}
				}
			}
			else search(x+1);
			guo[i]=0;
			numguo[x]=0;
		}
	}
}

int main()
{
	cin>>n;
	search(1);//从第一个开始找
	if(!c)	cout<<"-1";//如果没可能就输出“-1”
	return 0;
}

  这些代码中我用了很多的函数,这样节约了代码长度,也更加方便(个人觉得)。

回溯就是这个中心思想,一步步往下搜,一层层的搜,直到搜完或找到结果为止。

其实上面两道题都是很水的基础,再往后还有回溯遍历图、树等等等等。。

ending。。。

时间: 2025-01-06 00:58:11

回溯算法————n皇后、素数串的相关文章

回溯算法之八皇后问题

1 package 回溯; 2 3 public class 八皇后递归回溯 { 4 5 private int length; //皇后数量 6 private int sum; //总方案数 7 private int num[]; //存放皇后的一维数组 8 9 public 八皇后递归回溯() { 10 length = 8; 11 sum=0; 12 num = new int[length + 1]; 13 } 14 15 public boolean check(int x) {

8皇后以及N皇后算法探究,回溯算法的JAVA实现,非递归,循环控制及其优化

上两篇博客 8皇后以及N皇后算法探究,回溯算法的JAVA实现,递归方案 8皇后以及N皇后算法探究,回溯算法的JAVA实现,非递归,数据结构“栈”实现 研究了递归方法实现回溯,解决N皇后问题,下面我们来探讨一下非递归方案 实验结果令人还是有些失望,原来非递归方案的性能并不比递归方案性能高 代码如下: package com.newflypig.eightqueen; import java.util.Date; /** * 使用循环控制来实现回溯,解决N皇后 * @author [email pr

回溯算法解八皇后问题(java版)

八皇后问题是学习回溯算法时不得不提的一个问题,用回溯算法解决该问题逻辑比较简单. 下面用java版的回溯算法来解决八皇后问题. 八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例.该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行.同一列或同一斜线上,问有多少种摆法. 思路是按行来规定皇后,第一行放第一个皇后,第二行放第二个,然后通过遍历所有列,来判断下一个皇后能否放在该列.直到所有皇后都放完,或者放哪

【八皇后问题】 回溯算法

回溯算法:回溯算法实际上是一个类似枚举的搜索尝试方法,它的思想是在搜索尝试中寻找问题的解,当发现不满足求解条件时,就“回溯”返回,尝试别的路径.之前介绍的基础算法中的贪婪算法,动态规划等都具有“无后效性”,也就是在分段处理问题时,某状态一旦确定,将不再改变.而多数问题很难找到"无后效性”的阶段划分和相应决策,而是通过深入搜索尝试和回溯操作完成的. 八皇后问题:8*8的国际象棋棋盘中放八个皇后,是任意两个皇后不能互相吃掉.规则:皇后能吃掉同一行,同一列,同一对角线的任意棋子. 模型建立:不妨设八个

C++回溯算法Demo:以4皇后问题为例

回溯算法实际上是构造一棵推理树,并由树的叶子节点反向输出历史步骤: 其中,树的构建过程较为复杂:一种简化的方法是使用链表连接和构造各个节点的关系: 以4皇后问题为例,采用C++ vector容器--避免使用指针(当然换成了整数来代替指针表达对象的位置),解决了该问题.整体算法思路清晰,便于理解. 见代码:与书中不同,此代码实际输出的是所有4皇后问题的不同走法 //title:4皇后问题的回溯算法求解 //Demo: 1)回溯算法实现4皇后问题:2)难点:树形结构的表达:3)用线性容器表达树形结构

经典回溯算法(八皇后问题)详解

八皇后问题,是一个古老而著名的问题,是回溯算法的典型例题.该问题是十九世纪著名的数学家高斯1850年提出: 在8X8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行.同一列或同一斜线上 (斜率为1),问有多少种摆法.高斯认为有76种方案. 1854年在柏林的象棋杂志上不同的作者发表了40种不同的解,后来有人用图论的方法解出92种结果. 计算机发明后,有多种方法可以解决此问题. 算法思路:    首先我们分析一下问题的解,我们每取出一个皇后,放入一行,共有八种不同的放法

回溯算法-C#语言解决八皇后问题的写法与优化

结合问题说方案,首先先说问题: 八皇后问题:在8X8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行.同一列或同一斜线上,问有多少种摆法. 嗯,这个问题已经被使用各种语言解答一万遍了,大多还是回溯法解决的. 关于回溯算法:个人理解为就是优化的穷举算法,穷举算法是指列出所有的可能情况,而回溯算法则是试探发现问题"剪枝"回退到上个节点,换一条路,能够大大提高求解效率. 具体到8皇后问题上来说,需要考虑以下几点: 1)将8个皇后定义为8行中的相对位置来标识,考虑增

C语言回溯算法解决N皇后问题

回溯算法的模型是 x++, not satisfy ? x-- : continue. 代码中x作列号,y[x]保存第x列上皇后放置的位置. 1 #include<stdio.h> 2 #include<math.h> 3 #define N 5 4 int position_check(int,int*); 5 void print_board(int count,int* y); 6 int main() 7 { 8 int y[N]= {0}; //记录每列上的皇后放的位置

8皇后问题SQL求解(回溯算法)

问题 八皇后问题是一个古老而著名的问题,是回溯算法的典型例题.该问题是十九世纪著名的数学家高斯1850年提出:在8X8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行.同一列或同一斜线上,问有多少种摆法 百度来的代码 回溯法用递归实现八皇后解法 declare type t_queen is varray(8) of number; queen t_queen := t_queen(1, 2, 3, 4, 5, 6, 7, 8); l_num number := 0;