DLX演算法解數獨遊戲 Java版

來源:互聯網
上載者:User

使用DLX演算法解數獨遊戲。
初學Java,演算法代碼是由C代碼轉換的。
DLX.java是演算法類,Sudoku.java是介面類。
解號稱世界上最難的數獨用時10ms以內。


演算法詳解

Sudoku 數獨 Dancing Links模板

使用方法

int n = 9;
DLX dlx = new DLX(n * n * n + 1, 4 * n * n);
                dlx.setNum(5);//最多求5個解,預設為2
                dlx.solve(data);//int data[9][9];

                List<int[][]> solutions = dlx.getSolutions();


代碼下載

https://code.google.com/p/sudoku-dlx/source/checkout

DLX.java

import java.util.ArrayList;import java.util.List;public class DLX{private static final int ROW = 4096 + 50;private static final int COL = 1024 + 50;private static final int N = 4 * 9 * 9;private static final int m = 3;DLXNode row[] = new DLXNode[ROW];DLXNode col[] = new DLXNode[COL];DLXNode head;private int n;private int num = 2;private int size[] = new int[COL];int data[][] = new int[9][9];List<int[][]> solutions;public DLX(int r, int c){n = m * m;head = new DLXNode(r, c);head.U = head.D = head.L = head.R = head;for (int i = 0; i < c; ++i){col[i] = new DLXNode(r, i);col[i].L = head;col[i].R = head.R;col[i].L.R = col[i].R.L = col[i];col[i].U = col[i].D = col[i];size[i] = 0;}for (int i = r - 1; i > -1; --i){row[i] = new DLXNode(i, c);row[i].U = head;row[i].D = head.D;row[i].U.D = row[i].D.U = row[i];row[i].L = row[i].R = row[i];}}public void addNode(int r, int c){DLXNode p = new DLXNode(r, c);p.R = row[r];p.L = row[r].L;p.L.R = p.R.L = p;p.U = col[c];p.D = col[c].D;p.U.D = p.D.U = p;++size[c];}public void addNode(int i, int j, int k){int r = (i * n + j) * n + k;addNode(r, i * n + k - 1);addNode(r, n * n + j * n + k - 1);addNode(r, 2 * n * n + block(i, j) * n + k - 1);addNode(r, 3 * n * n + i * n + j);}int block(int x, int y){return x / m * m + y / m;}public void cover(int c){if (c == N)return;col[c].delLR();DLXNode R, C;for (C = col[c].D; C != col[c]; C = C.D){if (C.c == N)continue;for (R = C.L; R != C; R = R.L){if (R.c == N)continue;--size[R.c];R.delUD();}C.delLR();}}public void resume(int c){if (c == N)return;DLXNode R, C;for (C = col[c].U; C != col[c]; C = C.U){if (C.c == N)continue;C.resumeLR();for (R = C.R; R != C; R = R.R){if (R.c == N)continue;++size[R.c];R.resumeUD();}}col[c].resumeLR();}public boolean solve(int depth){if (head.L == head){int solution[][] = new int[n][n];for (int i = 0; i < n; ++i)for (int j = 0; j < n; ++j)solution[i][j] = data[i][j];solutions.add(solution);if (solutions.size() == num)return true;return false;}int minSize = 1 << 30;int c = -1;DLXNode p;for (p = head.L; p != head; p = p.L)if (size[p.c] < minSize){minSize = size[p.c];c = p.c;}cover(c);for (p = col[c].D; p != col[c]; p = p.D){DLXNode cell;p.R.L = p;for (cell = p.L; cell != p; cell = cell.L){cover(cell.c);}p.R.L = p.L;int rr = p.r - 1;data[rr / (n * n)][rr / n % n] = rr % n + 1;if (solve(depth + 1))return true;p.L.R = p;for (cell = p.R; cell != p; cell = cell.R)resume(cell.c);p.L.R = p.R;}resume(c);return false;}public boolean solve(int data[][]){init(data);return solve(0);}public void init(int data[][]){solutions = new ArrayList<int[][]>();int i, j, k;for (i = 0; i < n; ++i)for (j = 0; j < n; ++j){if (data[i][j] > 0){addNode(i, j, data[i][j]);} else{for (k = 1; k <= n; ++k)addNode(i, j, k);}}}public void setNum(int num){this.num = num;}public int getNum(){return num;}public List<int[][]> getSolutions(){return solutions;}}class DLXNode{int r,c;DLXNode U,D,L,R;DLXNode(){r = c = 0;}DLXNode(int r, int c){this.r = r;this.c = c;}DLXNode(int r, int c, DLXNode U, DLXNode D, DLXNode L, DLXNode R){this.r = r;this.c = c;this.U = U;this.D = D;this.L = L;this.R = R;}public void delLR(){L.R = R;R.L = L;}public void delUD(){U.D = D;D.U = U;}public void resumeLR(){L.R = R.L = this;}public void resumeUD(){U.D = D.U = this;}}

Sudoku.java

import java.awt.*;import java.awt.event.*;import javax.swing.*;import javax.swing.border.LineBorder;import javax.swing.border.TitledBorder;import javax.swing.plaf.basic.BasicArrowButton;import javax.swing.text.*;public class Sudoku extends JPanel{/** *  */private static final long serialVersionUID = 1L;private static final int width = 9;private static final int height = 9;private int data[][] = new int[height][width];private String infoStr = "";JButton solve = new JButton("Solve"), reset = new JButton("Reset"), clean = new JButton("Clean");BasicArrowButton right = new BasicArrowButton(BasicArrowButton.EAST), left = new BasicArrowButton(BasicArrowButton.WEST);JTextField sudokus[][] = new JTextField[height][width];JTextPane info = new JTextPane();java.util.List<int[][]> solutions;private int solutionIdx = 0;Sudoku(){setLayout(null);for (int r = 0; r < 3; ++r){for (int c = 0; c < 3; ++c){JPanel jp = new JPanel();jp.setLayout(null);jp.setBounds(r * 95 + 5, c * 95 + 5, 95, 95);jp.setBorder(new LineBorder(Color.black));for (int x = 0; x < 3; ++x)for (int y = 0; y < 3; ++y){int j = r * 3 + x, i = c * 3 + y;sudokus[i][j] = new JTextField();sudokus[i][j].setBounds(30 * x + 5, 30 * y + 5, 25, 25);sudokus[i][j].setDocument(new NumberLenghtLimitedDmt(1));jp.add(sudokus[i][j]);}add(jp);}}solve.setBounds(85, 300, 75, 25);solve.addActionListener(new SolveAL());add(solve);reset.setBounds(175, 300, 75, 25);reset.addActionListener(new ResetAL());add(reset);clean.setBounds(265, 300, 75, 25);clean.addActionListener(new cleanAL());add(clean);left.setVisible(false);left.setBounds(170, 330, 50, 25);left.addActionListener(new prevAL());add(left);right.setVisible(false);right.setBounds(230, 330, 50, 25);right.addActionListener(new nextAL());add(right);JScrollPane jsp = new JScrollPane(info);info.setEditable(false);jsp.setBounds(300, 5, 140, 285);jsp.setBorder(new TitledBorder("Info"));add(jsp);}public boolean solve(){int i, j;for (i = 0; i < height; ++i){for (j = 0; j < width; ++j){try{data[i][j] = Integer.parseInt(sudokus[i][j].getText());sudokus[i][j].setEditable(false);} catch (NumberFormatException e){data[i][j] = 0;sudokus[i][j].setEnabled(false);}}}int n = 9;long startTime = System.currentTimeMillis();DLX dlx = new DLX(n * n * n + 1, 4 * n * n);dlx.setNum(5);dlx.solve(data);solutions = dlx.getSolutions();if (solutions.size() > 1)infoStr += "Find multi solutions.\n";else if (solutions.size() > 0)infoStr += "Find one solution.\n";elseinfoStr += "Cannot find a solution.\n";infoStr += "Used time: " + (System.currentTimeMillis() - startTime) + " ms\n";return update();}public void reset(int data[][]){solve.setEnabled(true);int i, j;for (i = 0; i < height; ++i){for (j = 0; j < width; ++j){sudokus[i][j].setEnabled(true);sudokus[i][j].setEditable(true);if (data[i][j] == 0){sudokus[i][j].setText("");} else{sudokus[i][j].setText(Integer.toString(data[i][j]));}}}}boolean update(){info.setText(infoStr);if (solutionIdx >= solutions.size())return false;left.setVisible(true);right.setVisible(true);int i, j;int solution[][] = solutions.get(solutionIdx);for (i = 0; i < height; ++i){for (j = 0; j < width; ++j){sudokus[i][j].setText(Integer.toString(solution[i][j]));}}return true;}public static void inFrame(JPanel jp, int width, int height){String title = "Sudoku";JFrame frame = new JFrame(title);frame.addWindowListener(new WindowAdapter() {public void windowClosing(WindowEvent e){System.exit(0);}});frame.getContentPane().add(jp, BorderLayout.CENTER);frame.setLocationByPlatform(true);frame.setSize(width, height);frame.setResizable(false);frame.setVisible(true);}public static void main(String[] args){int data[][] = { { 8, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 3, 6, 0, 0, 0, 0, 0 }, { 0, 7, 0, 0, 9, 0, 2, 0, 0 },{ 0, 5, 0, 0, 0, 7, 0, 0, 0 }, { 0, 0, 0, 0, 4, 5, 7, 0, 0 }, { 0, 0, 0, 1, 0, 0, 0, 3, 0 },{ 0, 0, 1, 0, 0, 0, 0, 6, 8 }, { 0, 0, 8, 5, 0, 0, 0, 1, 0 }, { 0, 9, 0, 0, 0, 0, 4, 0, 0 }, };Sudoku sudoku = new Sudoku();sudoku.reset(data);inFrame(sudoku, 450, 400);}class SolveAL implements ActionListener{public void actionPerformed(ActionEvent e){infoStr += "Start solve this sudoku.\n";info.setText(infoStr);solve.setEnabled(false);solve();}}class ResetAL implements ActionListener{public void actionPerformed(ActionEvent e){infoStr += "Reset sudoku data.\n";info.setText(infoStr);left.setVisible(false);right.setVisible(false);reset(data);}}class cleanAL implements ActionListener{public void actionPerformed(ActionEvent e){infoStr = "Clean sudoku data.\n";info.setText(infoStr);solve.setEnabled(true);left.setVisible(false);right.setVisible(false);int i, j;for (i = 0; i < height; ++i){for (j = 0; j < width; ++j){sudokus[i][j].setText("");sudokus[i][j].setEnabled(true);sudokus[i][j].setEditable(true);}}}}class prevAL implements ActionListener{public void actionPerformed(ActionEvent e){int size = solutions.size();if(size > 0){solutionIdx = (solutionIdx - 1 + size) % size;infoStr += "The " + (solutionIdx+1) + "th solution.\n";update();}}}class nextAL implements ActionListener{public void actionPerformed(ActionEvent e){int size = solutions.size();if(size > 0){solutionIdx = (solutionIdx + 1) % size;infoStr += "The " + (solutionIdx+1) + "th solution.\n";update();}}}class NumberLenghtLimitedDmt extends PlainDocument{/** *  */private static final long serialVersionUID = 1L;private int limit;public NumberLenghtLimitedDmt(int limit){super();this.limit = limit;}public void insertString(int offset, String str, AttributeSet attr) throws BadLocationException{if (str == null){return;}if ((getLength() + str.length()) <= limit){char[] upper = str.toCharArray();int length = 0;for (int i = 0; i < upper.length; i++){if (upper[i] >= '0' && upper[i] <= '9'){upper[length++] = upper[i];}}super.insertString(offset, new String(upper, 0, length), attr);}}}}
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.