n皇后算法

龙通科技笔试题里面有这样一道题:在一个n×n的棋盘上,放置n个不能互相捕捉的国际象棋“皇后”的所有布局。
以下是n皇后的算法,请完成填空部分:

public class Queen {
	private int n;
	private int[] queenPos;
	private double num = 0; // 记录共有多少种摆法

	Queen(int d) {
		n = d;
		queenPos = new int[d];
	}
	// 放置皇后的方法
	public void place(int row) {
		int i = 0;
		if (row == n) {
			           **1**        ;
		} else {
			for (i = 0; i < n; i++) {
				queenPos[row] = i;
				if (legality(row))
					     **2**            ;
			}
		}
	}
	// 判断布局是否合法
	private boolean legality(int list) {
		if (list == 0)
			return true;
		for (int i = 0; i < list; i++) {
			if (queenPos[i] == queenPos[list])
				          **3**         ;
			if (           **4**       )
				return false;
		}
		return true;
	}
	// 测试方法
	public static void main(String[] args) {
		System.out.println("输入个数n:");
		Scanner in = new Scanner(System.in);
		int n = in.nextInt();
		try {
			Queen q = new Queen(n);
			q.place(0);
			System.out.println(n + "*" + n + "时," + "共有" + q.num + "种可能摆法。" );
			System.out.println("OK!");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}}

是一个填空题,程序填空,总共也就4个空,但是真的很让人头大,如果不了解他的程序思想,完全是一头雾水。比自己写一个还难的感觉(回想一下平时工作中改前辈们留下的石山)。
填写完整的代码(加了些打桩)如下:

package hashMap;

import java.text.DecimalFormat;
import java.util.Scanner;

//5、在一个n×n的棋盘上,放置n个不能互相捕捉的国际象棋“皇后”的所有布局。
//以下是n皇后的算法,请完成填空部分:
public class Queen {
	private int n;
	private int[] queenPos;
	private double num = 0; // 记录共有多少种摆法

	Queen(int d) {
		n = d;
		queenPos = new int[d];
	}

	// 测试方法
	public static void main(String[] args) {
		//System.out.println("输入个数n:");
		// Scanner in = new Scanner(System.in);
		int n = 12;// in.nextInt();
		try {
			Queen q = new Queen(n);
			q.place(0);
			System.out.println(n + "*" + n + "时," + "共有" + q.num + "种可能摆法。");
			System.out.println("共判断了"+q.panduan+"次");
			double d=Math.pow(n, n);
			System.out.println("正常需要判断"+new DecimalFormat("#,##0.00").format(d)+"次");
			System.out.println("OK!");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	int panduan=0;
	// 放置皇后的方法
	public void place(int row) {
		int i = 0;
		if (row == n) {
			num++;
			printQ】、
			ueen();
		} else {
			for (i = 0; i < n; i++) {
				queenPos[row] = i;
				if (legality(row))//当前行放到第i列合法,才判断下一行
					place(row + 1);
				//否则什么都没做,会尝试将当前行放到i++,下一列上
			}
			//这边for循环走完是什么意思呢?
			//for循环出去之后place方法也结束了
			//回到了调place方法的地方,是上一行合法之后调的
		}
		//我们看看:最后一个
		//printQueen();
	}

	private void printQueen() {
		System.out.println("**************第" + num + "种解法:");
		for (int i = 0; i < queenPos.length; i++) {
			for (int j = 0; j < n; j++) {
				if (j == queenPos[i]) {
					System.out.print(" # ");
				} else {
					System.out.print(" * ");
				}
			}
			System.out.println();
		}

	}

	// 判断布局是否合法
	private boolean legality(int list) {
		panduan++;
		if (list == 0)
			return true;//第一行没有比较的,默认合法(其实没必要,因为for循环会直接出来,然后在下面会return true)
		for (int i = 0; i < list; i++) {
			if (queenPos[i] == queenPos[list])
				return false;// 不能在一行
			if (queenPos[i] - queenPos[list] == (i - list) || queenPos[i] - queenPos[list] == -(i - list))
				return false;// 不能在一斜行
		}
		return true;
	}

}

程序用到了递归调用的思想,大大简化了对内存的消耗以及避免了程序结构的臃肿。
主要体现在合法性判断上:按照一个正常的思想,我们要判断有多少种合法,那就把所有的可能都找到嘛!然后一个个棋盘布局的判断不就可以了?但是,那样判断----电脑扛不住!!!我们算算如果一个个的判断,我们需要的判断次数是8888888*8,这是一个很可怕的数字,不管内存占用如何,首先时间上就扛不住。其次,假设现在把n=12,那么判断次数直接上升2个数量级,100倍的耗时增加。
如下:

**************第14200.0种解法:
 *  *  *  *  *  *  *  *  *  *  *  # 
 *  *  *  *  *  *  *  *  *  #  *  * 
 *  *  *  *  *  *  *  #  *  *  *  * 
 *  *  *  *  #  *  *  *  *  *  *  * 
 *  *  #  *  *  *  *  *  *  *  *  * 
 #  *  *  *  *  *  *  *  *  *  *  * 
 *  *  *  *  *  *  #  *  *  *  *  * 
 *  #  *  *  *  *  *  *  *  *  *  * 
 *  *  *  *  *  *  *  *  *  *  #  * 
 *  *  *  *  *  #  *  *  *  *  *  * 
 *  *  *  #  *  *  *  *  *  *  *  * 
 *  *  *  *  *  *  *  *  #  *  *  * 
12*12时,共有14200.0种可能摆法。
共判断了10103868次
正常需要判断8,916,100,448,256.00次
OK!

注意正常判断和这样判断的次数差距相差一万倍。
8*8的:

**************第92.0种解法:
 *  *  *  *  *  *  *  # 
 *  *  *  #  *  *  *  * 
 #  *  *  *  *  *  *  * 
 *  *  #  *  *  *  *  * 
 *  *  *  *  *  #  *  * 
 *  #  *  *  *  *  *  * 
 *  *  *  *  *  *  #  * 
 *  *  *  *  #  *  *  * 
8*8时,共有92.0种可能摆法。
共判断了15720次
正常需要判断16,777,216.00次
OK!

相差100倍。
但是,即使已经如此优化了当n=20时,电脑还是没有在一分钟内给我答案,所以这个n增加一,运行时间都要接近指数增加,好可怕。
他的优化是怎么做到的呢?首先判断第一行的每个位置,是否合法(第一行都是合法的),然后判断第二行的位置是否合法,如果不合法,那么就不用去递归下面行的判断了,一下子省去了许多运算。肉眼可见的,1/8 * 2(3)/8的位置上都不用判断(当然不止这么点)。所以速度得到了巨大的提升。
所以说,一个好的算法,真的是太重要了。一定要培养这种寻找好的算法解决问题的习惯。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值