问题应用:N皇后问题
算法主要思想:动态规划(构建树解)、BFS
算法核心代码实现:
1 //https://www.cnblogs.com/cheng2839 2 class QueensContainer { 3 int n = -1;//n代表容器大小,及放置n个皇后 4 int[][] containers; //容器;0:可放置,1:皇后,-1:不可放置 5 State solvedTree; 6 List<int[][]> result = new ArrayList<>(); 7 8 public QueensContainer(int n) { 9 this.n = n; 10 containers = new int[n][n]; 11 12 State solvedTreeRoot = new State(); 13 solvedTreeRoot.cs = this.containers; 14 for (int i = 0; i < containers.length; i++) { 15 State s = new State(); 16 s.h++; 17 int[][] cs = clone(containers); 18 cs[0][i] = 1; 19 update(0, i, cs); 20 s.cs = cs; 21 solvedTreeRoot.children.add(s); 22 } 23 this.buildSolvedTree(solvedTreeRoot.children); 24 25 this.solvedTree = solvedTreeRoot; 26 } 27 28 class State { 29 int h = 0; 30 int[][] cs; 31 List<State> children = new ArrayList<>(); 32 } 33 34 //原文:https://www.cnblogs.com/cheng2839 35 void buildSolvedTree(List<State> root) { 36 if (null == root || root.size() == 0) 37 return; 38 for (State state : root) { 39 int h = state.h; 40 if (h == state.cs.length) 41 continue; 42 43 int[] is = state.cs[h]; 44 for (int i = 0; i < is.length; i++) { 45 if (is[i] == 0) { 46 State s = new State(); 47 s.h = h + 1; 48 int[][] cs = clone(state.cs); 49 cs[h][i] = 1; 50 update(h, i, cs); 51 s.cs = cs; 52 state.children.add(s); 53 } 54 } 55 buildSolvedTree(state.children); 56 } 57 } 58 59 //原文:https://www.cnblogs.com/cheng2839 60 void bfs(List<State> root) { 61 if (null == root || root.size() == 0) 62 return; 63 for (State s : root) { 64 if (null == s.children || s.children.size() == 0) { 65 int n = 0; 66 for (int i = 0; i < s.cs.length; i++) { 67 for (int j = 0; j < s.cs[i].length; j++) { 68 n += s.cs[i][j]==1 ? 1 : 0; 69 } 70 } 71 if (n == s.cs.length) 72 result.add(s.cs); 73 continue; 74 } 75 bfs(s.children); 76 } 77 } 78 79 //第i,j位置放置皇后,更新容器 80 //原文:https://www.cnblogs.com/cheng2839 81 boolean update(int i, int j, int[][] con) { 82 for (int k = 0; k < con.length; k++) { 83 for (int l = 0; l < con[k].length; l++) { 84 int d = con[k][l]; 85 if (k == i && l == j) { 86 continue; 87 } 88 89 boolean dead = false; 90 if (k == i) { 91 dead = true; 92 } 93 if (l == j) { 94 dead = true; 95 } 96 if (k-i == l-j) { 97 dead = true; 98 } 99 if (k-i == j-l) { 100 dead = true; 101 } 102 if (dead && d == 0) { 103 con[k][l] = -1; 104 continue; 105 } 106 if (dead && d == -1) { 107 continue; 108 } 109 if (dead && d == 1) { 110 return false; 111 } 112 } 113 } 114 return true; 115 } 116 117 public void print(int[][] con) { 118 StringBuilder stringBuilder = new StringBuilder(); 119 for (int i = 0; i < con.length; i++) { 120 for (int j = 0; j < con[i].length; j++) { 121 stringBuilder.append(con[i][j]==-1?0:con[i][j]); 122 if (j < con[i].length-1) { 123 stringBuilder.append(", "); 124 } 125 } 126 if (i < con.length-1) { 127 stringBuilder.append(" "); 128 } 129 } 130 System.out.println(stringBuilder.toString()); 131 } 132 133 int[][] clone(int[][] con) { 134 int[][] newCon = new int[con.length][con[0].length]; 135 for (int i = 0; i < con.length; i++) { 136 for (int j = 0; j < con[i].length; j++) { 137 newCon[i][j] = con[i][j]; 138 } 139 } 140 return newCon; 141 } 142 }
结果展示:
(输出分控制台打印和可视图形化)可视化图形可通过按键(上下/左右)查看结果
import javax.swing.*; import java.awt.*; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.util.ArrayList; import java.util.List; /** * @Description N皇后问题 * @Author https://www.cnblogs.com/cheng2839 * @Date 2021年3月22日 * @Version v1.0 */ public class NQueens { static class MyFrame extends JPanel { JFrame jFrame = new JFrame(); static final int SIZE = 50; static final int L = 3; int[][] data = null; //一个解 static int DATA_INDEX = 0; static List<int[][]> result; //全部解 public MyFrame(int n, List<int[][]> result) { MyFrame.result = result; jFrame.setTitle(n+"皇后问题—第"+(DATA_INDEX+1)+"/"+result.size()+"个解"); data = result.get(DATA_INDEX); jFrame.setLayout(new CardLayout()); jFrame.setBounds(0, 0, 500, 500); this.setBackground(Color.WHITE); jFrame.addKeyListener(new KeyAdapter() { public void keyReleased(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_RIGHT || e.getKeyCode() == KeyEvent.VK_UP) { DATA_INDEX = Math.min(DATA_INDEX+1, result.size()-1); } else if (e.getKeyCode() == KeyEvent.VK_LEFT || e.getKeyCode() == KeyEvent.VK_DOWN) { DATA_INDEX = Math.max(DATA_INDEX-1, 0); } data = result.get(DATA_INDEX); jFrame.setTitle(n+"皇后问题—第"+(DATA_INDEX+1)+"/"+result.size()+"个解"); MyFrame.this.repaint(); } }); /*new Thread(()->{ while (true) this.repaint(50); }).start();*/ jFrame.add(this); jFrame.setVisible(true); jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } @Override public void paintComponent(Graphics g0) { if (null == data)return; Graphics2D g = (Graphics2D) g0; int w, h = -L; for (int i = 0; i < data.length; i++) { w = 0; h += L; for (int j = 0; j < data[i].length; j++) { g.setColor(data[i][j] == 1 ? Color.RED : Color.LIGHT_GRAY); g.fillRect(i * SIZE + h, j * SIZE + w, SIZE, SIZE); w += L; } } } } public static void main(String[] args) { int n = 8; QueensContainer qc = new QueensContainer(n); QueensContainer.State root = qc.solvedTree; qc.bfs(root.children); List<int[][]> result = qc.result; //可视化图形界面 new MyFrame(n, result); //控制台打印方式 /*System.out.println("一共求出"+result.size()+"组解。"); for (int[][] rs : result) { qc.print(rs); System.out.print(" "); }*/ } }