算法解析之八皇后

先说说驱动吧,这是数据结构的作业,要是没有这作业的话,我今天还是不想写代码的,想放天假呢,奈何实验课已然排到了周日。。oh no。。

说一下作业要求吧:

§ 实验目的:通过求解皇后问题,熟悉深度优先搜索法 DFS (回 溯法( BacktrackingAlgorithms )技术。
§ 实验内容:
§ n 2 个方块排成 n n 列的正方形称为 n 元棋盘。如果两个皇后位于 n 元棋盘上的同一行、同一列或同一对角线上,则称它们在互相攻击。现要找出使棋盘上 n 个皇后互不攻击的布局。
§ 编制程序解决上述问题,以 n=6 运行程序,输出结果。
4 方法说明 ( 溯法):

定义一个数组 A[n],A[ i ] 表示第 i 行上的皇后所在的列数 , i =0,1,...,n-1
i 行与第 j 行上的皇后互不攻击的充要条件是: |A[ i ]-A[j]|==| i -j|;
算法概述 :

  初始时,各行皇后均放在第0,然后从第0行开始逐行布局;

  设前i-1行已布好,现考虑第i行皇后的位置,从其当前位置A[i]开始向右探察:

A[ i ]<=n-1, 则检查 i 行皇后与前 i-1 行皇后是否互不攻击。若有攻击,则 i 行皇后右移一位,重复这个过程;若无攻击,则 :
i <n-1 ,继续布下一行的皇后;
i =n-1 ,输出布局,然后将 n-1 行皇后右移一位,重复这个过程,寻找另一种布局。
A[ i ]>n-1 ,则将 i 行皇后放在第 0 列,回退一行,考虑第 i-1 行皇后与前 i-2 行皇后互不攻击的下一个位置。若已退到 -1 行,则结束。

算法语言描述:

for(inti=0;i<n;i++)A[i]=0;

i=0;

while(i>=0){

    if(A[i]<=n-1) {

  检测A[i]A[0]~A[i-1]是否有冲突;

  if(有冲突)A[i]++;

  else if(i<n-1)i++;

        else {输出布局;A[n-1]++;}

    }

    else { A[i]=0;i--;

       if(i>=0)A[i]++;

           }

}


啥还没写就这么多了。

好了现在一点点实现吧:

先写一个类EightQueue,然后声明两个构造函数,EightQueue()和EightQueue(int n),无参构造函数里边写this(6),有参的里边粘贴上要求给的代码。如图:


然后把中文的部分翻译一下,感觉目前还很简单。。上面说了i行与第j行上的皇后互不攻击的充要条件是:|A[i]-A[j]|==|i-j|;很明显这里是个循环检测,那最好写成一个方法,又因为下边有一个“有冲突”的判断,所以这个方法一定要有个返回值,这个返回值要赋值给一个标志符。所以再次声明一个boolean型变量HasCollide.创建方法CheckCollide(int i,int[]  A);充要条件写上去。

对于循环检测我一般是这样写的,先写一个,再循环,听不懂?代码解释:

if (Math.abs(A[i]-A[0])==Math.abs(i-0)) {
			return false;
		}
		else{
			return true;
		}
abs是求绝对值的,这样检测的是A[i]和A[0]的,然后上循环。

private boolean CheckCollide(int i, int[] A) {
		// TODO Auto-generated method stub
		boolean result = true;
		for (int j = 0; j < i - 1; j++) {
			if (Math.abs(A[i] - A[j]) == Math.abs(i - j)) {
				result = false;
			}
		}
		return result;
	}
好了这个检测方法就写完了,下面是输出布局,总觉得少点什么==,不会就这么简单吧。。想想这个输出布局要输出啥。。

恩,这个布局应该是A[i]的数据,顺便说一下,这个要求的代码风格很不舒服,整理之后如下:

EightQueue(int n){
		int [] A=new int[n];
		int i;
		boolean HasCollide=false;
		for(i=0;i<n;i++)
			A[i]=0;
		i=0;
		while(i>=0)
		{
		    if(A[i]<=n-1)
		    {
		    	HasCollide=CheckCollide(i,A);
		    	if(HasCollide)
		    	A[i]++;
		        else if(i<n-1)
		    	i++;
		        else {
		        	输出布局;
		        	A[n-1]++;
		        }
		    }
		    else { 
		    	A[i]=0; 
		    	i--;
		       if(i>=0)
		    	   A[i]++;
		          }
		}
	}

之前我的风格一直是if(){/r/n},最近因为写C#代码里边Vs有个插件叫intend guide,缩进指南,这样上下两个大括号之前会用虚线连起来,这样一下就能看出来这个循环是哪部分,刚才以我原来的风格确实看的有点乱,又整理成了C#的风格了。果然看着很方便。不说废话了,A[]是记录布局数据的,A[i]的数字就是说明第i行的棋子的位置,所以输出布局就简单多了。

写个方法Print(int [] A);

一个种棋叫啥来的忘了,反正棋子是用O和X表示的,觉得很显眼,这里就采用这个了。空的地方为O,棋子为X.两层循环。

private void Print(int[] a2) {
		// TODO Auto-generated method stub
		int j ;
		for (int i = 0; i < a2.length; i++) {
			for (j = 0; j < a2[i]; j++) {
				System.out.print("O");
			}
			System.out.print("X");
			for (; j < a2.length; j++) {
				System.out.println("O");
			}
		}
	}

这样,好了现在测试一下,==,发现个问题,啥玩意 都没输出来。我就说没有这么简单。。又到了激动人心的调bug的时候了。。

好,现在把在这个while循环的结束之后调用Print方法发现输出的是:

XOOOOOOXOOOOOOXOOOOOOXOOOOOOXOOOOOOXOOOOOO

也就是有两个问题。。1,这一行多了一个,这个好办。2,while循环很可能就没有执行。先解决第一个。


多输出了一个在第二个循环里改成length-1,第一个问题解决。

现在第二个问题:读代码发现while循环肯定执行了,下一步,找别的疑点。

分析一下代码觉得是检测冲突那里出现问题了。。于是加了一个输出:

	if (Math.abs(A[i] - A[j]) == Math.abs(i - j)) {
				result = false;
				System.out.println("dasd");
			}

发现完全没有输出。现在问题找到了,原因是?
再往上找一步,发现是循环都未启动过,输出一下i,发现传过来的i都是0.。汗。。

看题:A[i]<=n-1,则检查i行皇后与前i-1行皇后是否互不攻击。若有攻击,则i行皇后右移一位,重复这个过程;

N久之后,,自觉是自己的检测冲突写错了。马上改正,成功。。原因:老师给的结论就是错误的!!互不攻击的条件写错了她!!不过也赖我没动脑子。。不过这么关键的点上写错了条件直接耽误了十多分钟!

private boolean CheckCollide(int i, int[] A) {
		// TODO Auto-generated method stub
		boolean result = false;
		for (int j = 0; j < i; j++) {
			if (Math.abs(A[i] - A[j]) == Math.abs(i - j)||A[i]==A[j]) {
				result=true;
				break;
			}
		}
		return result;
	}






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值