皇后问题

昨晚, 想实现下N个皇后的问题. 写出思路, 然后代码, 结果调了很久都没有成功. 哪出错了呢. 

递归算法的思路如下:

  1. 从上到下按行逐一进行皇后的放置,所以不用考虑同一行有多个皇后的问题
  2. 将每一行的皇后位置放置在一个数组当中. 可用于位置判断以及结果输出
  3. 放置皇后时需有一判断位置是否安全的函数
    1. 是否同列
    2. 是否在对角线上
  4. 递归放置下一行, 若放置到最后一行时, 解数量加一 

以下是错误代码. 

#include <iostream>
#define N 4
intflag[N+1]={0};
bool	bSafe(int i, int j);
void  cq(int i);
int   count(0);
int   main()
{
  cq(1);
  std::cout<<count<<std::endl;
  system("pause");
}
//计算可行组合数
void cq(int i)
{
  for(int j=1; j <= N; j++)
    if(bSafe(i, j))
    {
      flag[i]=j;
      if (i < N)
        cq(++i);
      else
        count++;
    }
}
//判断指定位置是否安全
bool bSafe(int i, int j)
{
  for (int temp=1; temp<i; temp++)
  //同列或对角钱上则不安全
  if (j == flag[temp] || j-flag[temp] == temp-i || j-flag[temp] == i-temp)
    return false;
  return true;
}

  寻找错误中.... 持续更新中...

两个小时过去了, 终于找到错误了. 有两个地方.

错误一:

第24行:

cq(++i);

改为:

cq(i+1);

错误二:

第26行:

              count++;

改为:

 {
  count++;
  break;
}

分析:

错误一:

主要是关于++i 与 i+1作为参数时的区别, 其实作为参数传递给函数结果没有什么区别, 只是自己忘记了原来i在本定义域内还有用, 而++却改变了它本身的值. 那么i++呢, 和它的本意一样, 先将自身传给函数再自增. 在VS下测试是如此的, 不知道其它编译器如何. 

错误二:

在成功得到一种排列后没有退出循环. 这会造成什么后果使得结果不正确?

奇怪的是, 现在运行时没有break却依然可以得到正确的答案. 凌乱了我的思绪. 若count++后无break,则,在最后一行, 继续在for循环中, 顶多就多进行了N次判断, 按理说,这小于N的判断不会正确, 所以不会产生影响.那么之前的错误又是什么呢? 好吧, 我混乱了, 把上面的代码贴回去,只修改24行得到的结果是正确的. 至少break提高了一点点效率.

 

稍稍修改过的递归代码:/Files/uglyfly/8queen.rar 

 


 

以下为非递归算法的探索.


想法: 关于非递归算法, 则必需要有退回上一行的条件. 想的是: 如本行的所以位置都不可用,则退回上一行,从上一行的下一列继续开始判断. 若上一行已经是最后一列了, 遇再退一行.直到行数为0时退出.  如果标识所在行也要引进一个变量.   

以下为code:

int  findQ(int n)
{
	int now=1;//记录当前所在行, 从第一行开始
	int m=0;//总皇后数

	while (true)
	{
		int j;
		if (flag[now]==n)	now--;//若上一行已经是最后一列了, 遇再退一行
		if (now == 0) break;//若已经退到0行, 则说明放置完成

		for (j=flag[now]+1; j<=n; j++)
		{//放置皇后
			if(bSafe(now, j))
			{
				flag[now++]=j;//成功则当前行位置输入
				flag[now]=0;//下一行从0开始
				break;
			}
			if (j==n )	now--;//当前行都搜索完毕,返回上一行
		}

		if (now==n+1)
		{
			m++;
			printboard(m);	//输出到屏幕
		}
	}
	return m;
}

  

  

不足之处欢迎交流^^ 

posted @ 2012-05-18 14:35  樹下  阅读(259)  评论(0编辑  收藏  举报