1、数组的最大值和最小值
1.1、普通方法
普通算法的解决思路是:创建两个变量 max 和 min 分别记录数组中的最大值和最小值,它们的初始值都是数组中的第一个数字。从第 2 个数字开始遍历数组,每遇到一个比 max 大的数字,就将它存储到 max 变量中;每遇到一个比 min 小的数字,就将它存储到 min 变量中。直到遍历完整个数组,max 记录的就是数组中的最大值,min 记录的就是数组中的最小值。
1.2、分治算法解决
下图展示了用分治算法查找 {3, 7, 2, 1} 中最大值的实现过程:

分治算法的实现思路是:不断地等分数组中的元素,直至各个分组中元素的个数 ≤2。由于每个分组内的元素最多有 2 个,很容易就可以找出其中的最值(最大值或最小值),然后这些最值再进行两两比较,最终找到的最值就是整个数组中的最值。
代码实现:
public class Demo {public static int get_max(int [] arr,int left,int right) {//如果数组不存在或者数组内没有元素if (arr == null || arr.length == 0) {return -1;}//如果查找范围中仅有 2 个数字,则直接比较即可if(right - left <=1) {if(arr[left] >= arr[right]) {return arr[left];}return arr[right];}//等量划分成 2 个区域int middle = (right-left)/2 + left;int max_left = get_max(arr,left,middle);int max_right = get_max(arr,middle+1,right);if(max_left >= max_right) {return max_left;}else {return max_right;}}public static void main(String[] args) {int [] arr = new int[] { 3,7,2,1 };int max = get_max(arr,0,3);System.out.println("最大值:"+max);}}
程序结果:
2、汉诺塔问题
汉诺塔问题源自印度一个古老的传说,印度教的“创造之神”梵天创造世界时做了 3 根金刚石柱,其中的一根柱子上按照从小到大的顺序摞着 64 个黄金圆盘。梵天命令一个叫婆罗门的门徒将所有的圆盘移动到另一个柱子上,移动过程中必须遵守以下规则:
- 每次只能移动柱子最顶端的一个圆盘;
 - 每个柱子上,小圆盘永远要位于大圆盘之上;
 
图 1 给您展示了包含 3 个圆盘的汉诺塔问题:

一根柱子上摞着 3 个不同大小的圆盘,那么在不违反规则的前提下,如何将它们移动到另一个柱子上呢?图 2 给大家提供了一种实现方案:
图 2 汉诺塔问题的解决方案
汉诺塔问题中,3 个圆盘至少需要移动 7 次,移动 n 的圆盘至少需要操作 2n-1 次。
在汉诺塔问题中,当圆盘个数不大于 3 时,多数人都可以轻松想到移动方案,随着圆盘数量的增多,汉诺塔问题会越来越难。也就是说,圆盘的个数直接决定了汉诺塔问题的难度,解决这样的问题可以尝试用分治算法,将移动多个圆盘的问题分解成多个移动少量圆盘的小问题,这些小问题很容易解决,从而可以找到整个问题的解决方案。
分治算法解决汉诺塔问题
为了方便讲解,我们将 3 个柱子分别命名为起始柱、目标柱和辅助柱。实际上,解决汉诺塔问题是有规律可循的:
1) 当起始柱上只有 1 个圆盘时,我们可以很轻易地将它移动到目标柱上;
2) 当起始柱上有 2 个圆盘时,移动过程如下图所示:

图 3 移动两个圆盘
移动过程是:先将起始柱上的 1 个圆盘移动到辅助柱上,然后将起始柱上遗留的圆盘移动到目标柱上,最后将辅助柱上的圆盘移动到目标柱上。
3) 当起始柱上有 3 个圆盘时,移动过程如图 2 所示,仔细观察会发现,移动过程和 2 个圆盘的情况类似:先将起始柱上的 2 个圆盘移动到辅助柱上,然后将起始柱上遗留的圆盘移动到目标柱上,最后将辅助柱上的圆盘移动到目标柱上。
通过分析以上 3 种情况的移动思路,可以总结出一个规律:对于 n 个圆盘的汉诺塔问题,移动圆盘的过程是:
- 将起始柱上的 n-1 个圆盘移动到辅助柱上;
 - 将起始柱上遗留的 1 个圆盘移动到目标柱上;
 - 将辅助柱上的所有圆盘移动到目标柱上。
 
由此,n 个圆盘的汉诺塔问题就简化成了 n-1 个圆盘的汉诺塔问题。按照同样的思路,n-1 个圆盘的汉诺塔问题还可以继续简化,直至简化为移动 3 个甚至更少圆盘的汉诺塔问题。
代码实现:
public class Demo {// 统计移动次数public static int i = 1;public static void hanoi(int num, char sou, char tar, char sux) {// 如果圆盘数量仅有 1 个,则直接从起始柱移动到目标柱if (num == 1) {System.out.println("第" + i + "次:从" + sou + "移动到" + tar);i++;} else {// 递归调用 hanoi() 函数,将 num-1 个圆盘从起始柱移动到辅助柱上hanoi(num - 1, sou, sux, tar);// 将起始柱上剩余的最后一个大圆盘移动到目标柱上System.out.println("第" + i + "次:从" + sou + "移动到" + tar);i++;// 递归调用 hanoi() 函数,将辅助柱上的 num-1 圆盘移动到目标柱上hanoi(num - 1, sux, tar, sou);}}public static void main(String[] args) {// 以移动 3 个圆盘为例,起始柱、目标柱、辅助柱分别用 A、B、C 表示hanoi(3, 'A', 'B', 'C');}}
执行结果:
3、部分背包问题
在限定条件下,如何从众多物品中选出收益最高的几件物品,这样的问题就称为背包问题。
 
举个简单的例子,商店的货架上摆放着不同重量和价值的商品,一个小偷在商店行窃,他携带的背包只能装固定重量的商品,选择哪些商品才能获得最大的收益呢?这个问题就属于背包问题,限定条件是背包的承重,最终目标是令背包中存放的物品的总收益最高。
根据不同的限定条件,背包问题还可以有更细致的划分:
- 0-1 背包问题:每件物品都不可再分,要么整个装入背包,要么放弃,不允许出现类似“将物品的 1/3 装入背包”的情况;
 - 部分背包问题:每件物品是可再分的,即允许将某件物品的一部分(例如 1/3)放入背包;
 - 完全背包问题:挑选物品时,每件物品可以选择多个,也就是说不限物品的数量。
 - 多重背包问题:每件物品的数量是有严格规定的,比如物品 A 有 2 件,物品 B 有 3 件。
 
不同的背包问题,对应的解决方案也不相同。本节我们给大家讲解,如何用贪心算法解决部分背包问题。
3.1、贪心算法解决部分背包问题
假设商店中有 3 种商品,它们各自的重量和收益是:
- 商品 1:重量 10 斤,收益 60 元;
 - 商品 2:重量 20 斤,收益 100 元;
 - 商品 3:重量 30 斤,收益 120 元。
 
对于每件商品,顾客可以购买商品的一部分(可再分)。一个小偷想到商店行窃,他的背包最多只能装 50 斤的商品,如何选择才能获得最大的收益呢?
贪心算法解决此问题的思路是:计算每个商品的收益率(收益/重量),优先选择收益率最大的商品,直至所选商品的总重量达到 50 斤。
代码实现:
public class Demo {//根据收益率,对记录的商品进行从大到小排序public static void sort(float [] w, float [] p) {int length = w.length;//用v[]存商品的收益率float [] v = new float[length];for (int i=0;i<length;i++) {v[i] = p[i]/w[i];}//根据 v 数组记录的各个商品收益率的大小,同时对 w 和 p 数组进行排序for (int i = 0; i < length; i++) {for (int j = i + 1; j < length; j++) {if (v[i] < v[j]) {float temp = v[i];v[i] = v[j];v[j] = temp;temp = w[i];w[i] = w[j];w[j] = temp;temp = p[i];p[i] = p[j];p[j] = temp;}}}}/*贪心算法解决部分背包问题w:记录各个商品的总重量p:记录各个商品的总价值result:记录各个商品装入背包的比例W:背包的容量*/public static void fractional_knapsack(float []w, float []p, float []result, float W) {//根据收益率,重新对商品进行排序sort(w, p);int i=0;//从收益率最高的商品开始装入背包,直至背包装满为止while (W > 0) {float temp = W > w[i]?w[i]:W;result[i] = temp / w[i];W -= temp;i++;}}public static void main(String[] args) {//设定背包的容量float W = 50;//各个商品的重量float [] w = { 10,30,20 };//各个商品的价值float [] p = { 60,100,120 };//统计背包中商品的总收益float [] result = {0,0,0};//调用解决部分背包问题的函数fractional_knapsack(w,p,result,W);//统计背包中商品的总收益float values = 0;//根据 result 数组中记录的数据,决定装入哪些商品for (int i = 0; i < w.length; i++) {if (result[i] == 1) {System.out.println("总重量为"+w[i]+",总价值为"+p[i]+"的商品全部装入");values += p[i];}else if (result[i] == 0)System.out.println("总重量为"+w[i]+",总价值为"+p[i]+"的商品不装");else {System.out.println("总重量为"+w[i]+",总价值为"+p[i]+"的商品装入"+result[i]*100+"%");values += p[i] * result[i];}}System.out.print("最终收获的商品价值为"+values);}}
程序结果:
当背包最大承重为 50 斤时,商品一全部装入,商品二也全部装入,商品三装入 2/3,此时收益是最大的。
4、背包问题
商店的货架上摆放着不同重量和价值的商品,一个小偷在商店行窃,他携带的背包只能装固定重量的商品。装哪些商品才能获得最大的收益呢?在限定条件内找到最佳的物品组合,这样的问题统称为背包问题。
根据限定的条件不同,背包问题还可以细分:
- 部分背包问题:所有物品是可再分的,即允许将某件物品的一部分(例如 1/3)放入背包;
 - 0-1 背包问题:所有物品不可再分,要么整个装入背包,要么放弃,不允许出现“仅选择物品的 1/3 装入背包”的情况;
 - 完全背包问题:不对每一件物品的数量做限制,同一件物品可以选择多个装入背包;
 - 多重背包问题:每件物品的数量是有严格规定的,比如物品 A 有 2 件,物品 B 有 3 件。
 
前面章节中,我们学会了用贪心算法解决部分背包问题。本节,我们学习如何用动态规划算法解决 0-1 背包问题。
动态规划解决01背包问题
虚拟一个场景,商店中拥有 5 件商品,它们各自的重量和收益分别是:
- 商品 1:重量 1 斤,收益 1 元;
 - 商品 2:重量 2 斤,收益 6 元;
 - 商品 3:重量 5 斤,收益 18 元;
 - 商品 4:重量 6 斤,收益 22 元;
 - 商品 5:重量 7 斤,收益 28 元。
 
所有商品不可再分,顾客要么“整件”购买商品,要么放弃购买。一个小偷想窃取商品,他的背包只能装 11 斤商品,如何选择商品才能获得最大的收益呢?
动态规划算法解决此问题的核心思想是:背包承重 1 斤时所能获得的最大收益是很容易计算的,在此基础上,可以推算出背包承重 2 斤、3斤、…、14斤、15斤时所能获得的最大收益。建立如下这张表格,依次将各个商品装入不同承重的背包中,计算出它们所能获得的最大收益。
| 商品种类 | 背包承重 | |||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | |
| 不装任何商品 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 
| w1 = 1,v1 = 1 | ||||||||||||
| w2 = 2,v2 = 6 | ||||||||||||
| w3 = 5,v3 = 18 | ||||||||||||
| w4 = 6,v4 = 22 | ||||||||||||
| w5 = 7,v5 = 28 | 
表格中,wi 表示第 i 件商品的重量,vi 表示第 i 件商品的收益值。承重不同的各个背包尚未装入商品时,对应的收益值都为 0。
1) 首先考虑将商品一装入各个背包,除了承重值为 0 的背包,其它背包都能装入,且与不装任何商品相比,装入商品一后各个背包的收益更大,各个背包的收益值如表 2 所示:
| 商品种类 | 背包承重 | |||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | |
| 不装任何商品 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 
| w1 = 1,v1 = 1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 
| w2 = 2,v2 = 6 | ||||||||||||
| w3 = 5,v3 = 18 | ||||||||||||
| w4 = 6,v4 = 22 | ||||||||||||
| w5 = 7,v5 = 28 | 
我们用 f(n) 表示承重值为 n 的背包对应的最大收益。从算法的角度,各个背包收益值是这样计算的:f(1)=1+f(0)、f(2)=1+f(1)、…、f(11)=1+f(10),其中等号右侧表达式中的 1 指的是商品一的收益值,f(0)~f(10) 指的是不装任何商品时承重分别为 0~10 的背包对应的收益值,借助表格可以看到,它们的值都为 0。
2) 考虑将商品二装入各个背包,除了承重值为 0 和 1 的背包,其它背包都可以装入。我们可以计算出它们各自对应的收益值:
f(2) = 6 + f(0) = 1
f(3) = 6 + f(1) = 6
f(4) = 6 + f(2) = 7
…
f(9) = 6 + f(7) = 7
f(10) = 6 + f(8) = 7
f(11) = 6 + f(9) = 7
等号右侧 f(0)~f(9) 的值是表 2 中装入商品一的各个背包对应的收益值。相比装入商品一统计的各个背包的收益值,装入商品二能使提高各个背包的收益。更新后的表格为:
| 商品种类 | 背包承重 | |||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | |
| 不装任何商品 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 
| w1 = 1,v1 = 1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 
| w2 = 2,v2 = 6 | 0 | 1 | 6 | 7 | 7 | 7 | 7 | 7 | 7 | 7 | 7 | 7 | 
| w3 = 5,v3 = 18 | ||||||||||||
| w4 = 6,v4 = 22 | ||||||||||||
| w5 = 7,v5 = 28 | 
3) 考虑将商品三装入各个背包,除了承重值为小于 5 的背包,其它背包都可以装入。我们可以计算出它们各自对应的收益值:
f(5) = 18 + f(0)  = 18
f(6) = 18 + f(1) = 19
f(7) = 18 + f(2) = 24
f(8) = 18 + f(3) = 25
f(9) = 18 + f(4) = 25
f(10) = 18 + f(5) = 25
f(11) = 18 + f(6) = 25
等号右侧 f(0)~f(6) 的值是表 2 中装入商品二的各个背包对应的收益值。和装入商品二时统计的各个背包的收益值相比,装入商品三能提高各个背包的收益。更新后的表格为:
| 商品种类 | 背包承重 | |||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | |
| 不装任何商品 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 
| w1 = 1,v1 = 1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 
| w2 = 2,v2 = 6 | 0 | 1 | 6 | 7 | 7 | 7 | 7 | 7 | 7 | 7 | 7 | 7 | 
| w3 = 5,v3 = 18 | 0 | 1 | 6 | 7 | 7 | 18 | 19 | 24 | 25 | 25 | 25 | 25 | 
| w4 = 6,v4 = 22 | ||||||||||||
| w5 = 7,v5 = 28 | 
4) 采用同样的方法,我们可以将表 4 中缺失的数据补全,最终得到的表格为:
| 商品种类 | 背包承重 | |||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | |
| 不装任何商品 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 
| w1 = 1,v1 = 1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 
| w2 = 2,v2 = 6 | 0 | 1 | 6 | 7 | 7 | 7 | 7 | 7 | 7 | 7 | 7 | 7 | 
| w3 = 5,v3 = 18 | 0 | 1 | 6 | 7 | 7 | 18 | 19 | 24 | 25 | 25 | 25 | 25 | 
| w4 = 6,v4 = 22 | 0 | 1 | 6 | 7 | 7 | 18 | 22 | 24 | 28 | 29 | 29 | 40 | 
| w5 = 7,v5 = 28 | 0 | 1 | 6 | 7 | 7 | 18 | 22 | 28 | 29 | 34 | 35 | 40 | 
注意,并不是每试图装入一个新商品,背包的收益一定会提高。举个例子,承重为 7 斤的背包装入商品四时的最大收益是:f(7) = 22+f(1) = 23,装入商品三时最大的收益值为:f(7) = 18+f(2) = 24。因此,表 5 中承重 7 斤的背包装入商品 4 时对应的收益值仍为 24,并未发生改变。
代码实现:
public class Demo {static int N = 5;//商品的种类static int W = 11;//背包的承重//动态规划算法解决01背包问题public static void knapsack01(int [][] result , int [] w,int []v) {//逐个遍历每个商品for(int i=1;i<=N;i++) {//求出从 1 到 W 各个承重对应的最大收益for ( int j=1;j<=W;j++) {//如果背包承重小于商品总重量,则该商品无法放入背包,收益不变if(j<w[i]) {result[i][j] = result[i-1][j];}else {//比较装入该商品和不装该商品,哪种情况获得的收益更大,记录最大收益值result[i][j] = result[i - 1][j] > (v[i] + result[i - 1][j - w[i]]) ? result[i - 1][j] : (v[i] + result[i - 1][j - w[i]]);}}}}//追溯选中的商品public static void select(int [][] result , int [] w,int []v) {int n = N;int bagw = W;//逐个商品进行判断while(n>0) {//如果在指定承重下,该商品对应的收益和上一个商品对应的收益相同,则表明未选中if (result[n][bagw] == result[n - 1][bagw]) {n--;}else {//输出被选用商品的重量和价值System.out.print("("+w[n]+","+v[n]+") ");//删除被选用商品的承重,以便继续遍历bagw = bagw - w[n];n--;}}}public static void main(String[] args) {int [] w= {0,1 , 2 , 5 , 6 , 7}; //商品的重量int [] v ={0,1 , 6 , 18 , 22 , 28}; //商品的价值int [][] result = new int[N+1][W+1];knapsack01(result, w, v);;System.out.println("背包可容纳重量为 "+W+",最大收益为 "+result[N][W]);System.out.print("选择了");select(result, w,v);}}
程序结果:
5、迷宫问题
迷宫问题指的是:在给定区域内,找到一条甚至所有从某个位置到另一个位置的移动路线。举个简单的例子,如图 1 所示,在白色区域内找到一条(甚至所有)从起点到终点的路线。
迷宫问题就可以采用回溯算法解决,即从起点开始,采用不断“回溯”的方式逐一试探所有的移动路线,最终找到可以到达终点的路线。
回溯算法解决迷宫问题
以图 1 所示的迷宫为例,回溯算法解决此问题的具体思路是:
- 从当前位置开始,分别判断是否可以向 4 个方向(上、下、左、右)移动:
 - 选择一个方向并移动到下个位置。判断此位置是否为终点,如果是就表示找到了一条移动路线;如果不是,在当前位置继续判断是否可以向 4 个方向移动;
 - 如果 4 个方向都无法移动,则回退至之前的位置,继续判断其它的方向;
 - 重复 2、3 步,最终要么成功找到可行的路线,要么回退至起点位置,表明所有的路线都已经判断完毕。
 
程序中,我们可以用特殊的字符表示迷宫中的不同区域。例如,用 1 表示可以移动的白色区域,用 0 表示不能移动的黑色区域,图 1 的迷宫可以用如下的 0-1 矩阵来表示:
1 0 1 1 1
1 1 1 0 1
1 0 0 1 1
1 0 0 1 0
1 0 0 1 1
代码实现:
public class Demo {static boolean find = false;static int ROW = 5;static int COL = 5;//(row,col) 表示起点,(outrow,outcol)表示终点public static void maze_puzzle(char [][] maze, int row, int col, int outrow, int outcol) {maze[row][col] = 'Y'; // 将各个走过的区域标记为 Y//如果行走至终点,表明有从起点到终点的路线if (row == outrow && col == outcol) {find = true;System.out.println("成功走出迷宫,路线图为:");printmaze(maze);return ;}//尝试向上移动if (canMove(maze, row - 1, col)) {maze_puzzle(maze, row - 1, col, outrow, outcol);//如果程序不结束,表明此路不通,恢复该区域的标记maze[row - 1][col] = '1';}//尝试向左移动if (canMove(maze, row, col - 1)) {maze_puzzle(maze, row, col - 1, outrow, outcol);//如果程序不结束,表明此路不通,恢复该区域的标记maze[row][col - 1] = '1';}//尝试向下移动if (canMove(maze, row + 1, col)) {maze_puzzle(maze, row + 1, col, outrow, outcol);//如果程序不结束,表明此路不通,恢复该区域的标记maze[row + 1][col] = '1';}//尝试向右移动if (canMove(maze, row, col + 1)) {maze_puzzle(maze, row, col + 1, outrow, outcol);//如果程序不结束,表明此路不通,恢复该区域的标记maze[row][col + 1] = '1';}}//判断(row,col)区域是否可以移动public static boolean canMove(char [][] maze, int row, int col) {//如果目标区域位于地图内,不是黑色区域,且尚未移动过,返回 true:反之,返回 falsereturn row >= 0 && row <= ROW - 1 && col >= 0 && col <= COL - 1 && maze[row][col] != '0' && maze[row][col] != 'Y';}//输出行走路线public static void printmaze(char [][] maze) {for(int i=0;i<ROW;i++) {for(int j=0;j<COL;j++) {System.out.print(maze[i][j]+" ");}System.out.println();}}public static void main(String[] args) {char [][]maze = new char[][]{{'1','0','1','1','1'},{'1','1','1','0','1'},{'1','0','0','1','1'},{'1','0','0','1','0'},{'1','0','0','1','1'} };maze_puzzle(maze, 0, 0, ROW - 1, COL - 1);if (find == false) {System.out.print("未找到可行线路");}}}
程序结果:
多个 Y 组成的路线就是从起点到终点的可行路线。 
6、N皇后问题
N 皇后问题源自国际象棋,所有棋子中权力最大的称为皇后,它可以直着走、横着走、斜着走(沿 45 度角),可以攻击移动途中遇到的任何棋子。N 皇后问题的具体内容是:如何将 N 个皇后摆放在 N*N 的棋盘中,使它们无法相互攻击。
举个简单的例子,将 4 个皇后摆放在 4*4 的棋盘中,下图给出了一种摆放方式,各个皇后无论是直着走、横着走还是斜着走,都无法相互攻击。
Q 表示放置皇后的位置。
N 皇后问题可以用回溯算法解决,接下来就为您讲解具体的解决思路。
回溯算法解决N皇后问题
要想使 N 个皇后不相互攻击,应将它们放置在不同的行、不同的列、还不能位于同一条 45°(或 135°)角的斜线上。
回溯算法解决N皇后问题的具体思路是:将 N 个皇后逐一放置在不同的行,以“回溯”的方式逐一测试出每行皇后所在行的具体位置,最终确定所有皇后的位置。
 
代码实现:
import java.util.Scanner;public class Demo {static int[] q = new int[20];static int count = 0;public static void n_queens(int k, int n) {int j;if (k > n)print(n);else {for (j = 1; j <= n; j++) // 试探第k行的每一列,找到符合要求的列{if (isSafe(k, j)) {q[k] = j;n_queens(k + 1, n); // 在确认第 k 行皇后位置的前提下,继续测试下一行皇后的位置}}}}public static boolean isSafe(int k, int j) {int i;for (i = 1; i < k; i++) {// 如果有其它皇后位置同一列上,或者位于该位置的斜线位置上,则该位置无法使用if (q[i] == j || Math.abs(i - k) == Math.abs(q[i] - j))return false;}return true;}// 输出 N 皇后问题的解决方案public static void print(int n) {int i, j;count++;System.out.println("第 " + count + " 个解:");for (i = 1; i <= n; i++) // 行{for (j = 1; j <= n; j++) // 列{if (q[i] != j)System.out.print("x");elseSystem.out.print("Q");}System.out.println();}System.out.println();}public static void main(String[] args) {System.out.println("请输入皇后个数:");Scanner sc = new Scanner(System.in);int n = sc.nextInt();n_queens(1, n);System.out.println("共有 " + count + " 种摆放方式");}}
程序结果:
假设皇后的总个数为 4
