【算法设计与分析基础】八皇后问题

来源:互联网 发布:交响诗篇知乎 编辑:程序博客网 时间:2024/06/11 05:09

用Java实现八皇后问题的图形界面:

显示前请先按start键,然后按next键输出一个个的结果,slower和faster调节演示速度。


可以通过操作 → 输入来判断是否满足八皇后条件,输入格式:8个数字,两个数字之间空一格。



① R.java    定义全局变量。变量都被定义为静态。

static void sleep(double i)  暂停 i 秒钟

package eq;public class R {////////////    矩阵大小     /////////////////public static int rect_x = 50;public static int rect_y = 50;public static int rect_Height = 30;public static int rect_Width = 30;/////////////////////////////////////////public final static int n = 8;//八皇后问题/////////////   窗口大小      /////////////////public final static int frame_Height = rect_y + rect_Height*n + 100;public final static int frame_Width = rect_x + rect_Width * n + 50;public static ButtonPanel bp = new ButtonPanel();public static QueuePanel qp = new QueuePanel();public static SurfaceView sv;public static Deal d = new Deal();public static Input i = new Input();public static double sleeptime = 0.0;public static boolean displaychoice = false;public static int x;public static int y;public static boolean next = true;/** * 暂停一段时间 * @param i 单位秒 */public static void sleep(double i){try {Thread.sleep((int)(i*(double)1000));} catch (InterruptedException e) {// TODO 自动生成的 catch 块e.printStackTrace();};}}
② SurfaceView.java 主窗口,添加按钮面板和八皇后国际象棋面板后,就是整个图形界面。

package eq;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import javax.swing.JFrame;import javax.swing.JMenu;import javax.swing.JMenuBar;import javax.swing.JMenuItem;public class SurfaceView extends JFrame implements ActionListener {public SurfaceView(){this.setSize(R.frame_Width,R.frame_Height);this.setDefaultCloseOperation(EXIT_ON_CLOSE);this.setTitle("QueueProblem");this.setLayout(null);R.bp.setBounds(0,0,R.frame_Width,R.bp.bt.Box_Height+10);this.add(R.bp);R.qp.setBounds(0,R.bp.getHeight(),R.frame_Width,(int)((double)R.frame_Height*0.9));JMenuBar JMB =new JMenuBar();this.setJMenuBar(JMB);JMenu Item = new JMenu("操作");JMB.add(Item);JMenuItem input = new JMenuItem("输入");Item.add(input);input.addActionListener(this);this.add(R.qp);}@Overridepublic void actionPerformed(ActionEvent e) {if(e.getActionCommand().equals("输入")){R.i.setVisible(true);}}}
③ QueuePanel.java   八皇后国际象棋面板。

1. void isinthePanel(int a,int b,Graphics g)  如果是在八皇后面板内,那么就画一个圆

2. void paintchoice(Graphics g)

   当指向一个皇后棋子的时候,它会在它的横竖斜上画一个黑圆,需要设置R.java中的displaychoice=true。

3. void paint(Graphics g) JPanel等控件的绘画函数,可以用Graphics来画圆画正方形之类的图形。

4. void isQueue(double x,double y)判断该坐标是不是在八皇后面板内,是就令R.x=i;R.y=j;,否则就赋值-1。

5. void mouseMoved(MouseEvent e)鼠标移动过程中,如果指向了皇后棋子,就重绘面板图形,使其横竖斜上出现黑    圆圈,需要设置R.java中的displaychoice=true。

package eq;import java.awt.BasicStroke;import java.awt.Color;import java.awt.Font;import java.awt.Graphics;import java.awt.Image;import java.awt.event.MouseEvent;import java.awt.event.MouseMotionListener;import java.io.File;import java.io.IOException;import java.awt.Graphics2D;import javax.imageio.ImageIO;import javax.swing.JPanel;public class QueuePanel extends JPanel implements MouseMotionListener {//FFC995//CC813DString path = "";public QueuePanel(){this.setBackground(new Color(255,255,255));path = new File("").getAbsolutePath() + "\\queue.png";this.addMouseMotionListener(this);}public void rd(){this.repaint();}    void isinthePanel(int a,int b,Graphics g){int x = R.x + a;int y = R.y + b;int oval_x;int oval_y;if(x>=0 && x<R.n && y>=0 && y<R.n){oval_x = (R.rect_x + y*R.rect_Width)+(int)((double)R.rect_Width*0.4);//行    oval_y = (R.rect_y + x*R.rect_Height)+(int)((double)R.rect_Height*0.4);//列    g.drawOval(oval_x,oval_y ,(int)((double)R.rect_Height*0.2) ,(int)((double)R.rect_Width*0.2 ));    /*g.drawRect(R.rect_x + y * R.rect_Width,    R.rect_y + x * R.rect_Height,    R.rect_Width,        R.rect_Height);*/}}public void paintchoice(Graphics g){if(R.x!=-1 && R.y!=-1){int i;int oval_x;int oval_y;((Graphics2D)g).setStroke(new BasicStroke(2.0f));g.setColor(new Color(0,0,0));for(i=-1;++i<R.n;){oval_x = (R.rect_x+i*R.rect_Width)+(int)((double)R.rect_Width*0.4);//行    oval_y = (R.rect_y+R.x*R.rect_Height)+(int)((double)R.rect_Height*0.4);//列    g.drawOval(oval_x,oval_y ,(int)((double)R.rect_Height*0.2) ,(int)((double)R.rect_Width*0.2 ));            oval_x = (R.rect_x+R.y*R.rect_Width)+(int)((double)R.rect_Width*0.4);//行    oval_y = (R.rect_y+i*R.rect_Height)+(int)((double)R.rect_Height*0.4);//列    g.drawOval(oval_x,oval_y ,(int)((double)R.rect_Height*0.2) ,(int)((double)R.rect_Width*0.2 ));}int k;for(k=0;++k<R.n;){isinthePanel(k,k,g);isinthePanel(-k,k,g);isinthePanel(k,-k,g);isinthePanel(-k,-k,g);}}}public void paint(Graphics g){super.paint(g);int i,j;Image img = null;//g.drawString(path, 10, 10);try {img = ImageIO.read(new File(path));//img = ImageIO.read(getClass().getResource("/queue.png"));} catch (IOException e) {// TODO 自动生成的 catch 块e.printStackTrace();}g.setColor(new Color(0,0,0));g.setFont(new Font("Georgia",Font.PLAIN,20));g.drawString(String.valueOf((R.d.n)%(92)+1)+"\\"+"92",  R.rect_x, R.rect_y-3);for(i=-1;++i<R.n;){for(j=-1;++j<R.n;){if((i+j)%2==0){g.setColor(new Color(0xFF,0XC9,0X95));}else{g.setColor(new Color(0xCC,0X81,0X3D));}g.fillRect(R.rect_x + j * R.rect_Width,    R.rect_y + i * R.rect_Height,    R.rect_Width,    R.rect_Height);if(j == R.d.col[i]){      g.drawImage(img,          R.rect_x + j * R.rect_Width+3,           R.rect_y + i * R.rect_Height+3,           R.rect_Width-6,           R.rect_Height-6          , this);}}}if(R.displaychoice)paintchoice(g);}void isQueue(double x,double y){double i = (y-R.rect_x)/R.rect_Height;//行double j = (x-R.rect_y)/R.rect_Width;//列if( i>=0 && i< R.n && j>=0 && j< R.n){R.x = (int)i;R.y = (int)j;}else{R.x = -1;R.y = -1;}}@Overridepublic void mouseDragged(MouseEvent e) {// TODO 自动生成的方法存根}}
④ ButtonPanel.java  按钮面板。显示四个按钮next slower faster start。
package eq;import java.awt.Color;import java.awt.Font;import java.awt.Graphics;import java.awt.event.MouseEvent;import java.awt.event.MouseListener;import javax.swing.JPanel;public class ButtonPanel extends JPanel implements MouseListener {BoxText bt = new BoxText("next","华文琥珀",Font.PLAIN,20,0,0);BoxText bt1 = new BoxText("slower","华文琥珀",Font.PLAIN,20,bt.Box_Width+10,0);BoxText bt2 = new BoxText("faster","华文琥珀",Font.PLAIN,20,bt.Box_Width+bt1.Box_Width+20,0);BoxText bt3 = new BoxText("start","华文琥珀",Font.PLAIN,20,bt.Box_Width+bt1.Box_Width+bt2.Box_Width+30,0);boolean start = false;public ButtonPanel(){this.setBackground(new Color(255,255,255));this.addMouseListener(this);}public void paint(Graphics g){super.paint(g);bt.draw(g);bt1.draw(g);bt2.draw(g);bt3.draw(g);}@Overridepublic void mouseClicked(MouseEvent e) {// TODO 自动生成的方法存根}@Overridepublic void mousePressed(MouseEvent e) {// TODO 自动生成的方法存根}@Overridepublic void mouseReleased(MouseEvent e) {// TODO 自动生成的方法存根int x = e.getX();int y = e.getY();if(e.getButton()==e.BUTTON1){    /**     * 如果点击到了"next"按钮     */    if(start && R.next && bt.isClicked(x, y)){    R.next = false;    R.x = -1;    R.y = -1;    Thread t = new Thread(new Runnable(){    public void run(){    R.d.n++;    R.d.solve_next();    }    });    t.start();}    /**     * 如果点击到了"slower"按钮     */    if(bt1.isClicked(x, y)){    R.sleeptime+=0.1;    }    /**     * 如果点击到了"faster"按钮     */    if(bt2.isClicked(x, y)){    if(R.sleeptime>=0.1){       R.sleeptime-=0.1;    }    }    /**     * 如果点击到了"start"按钮     */    if(bt3.isClicked(x, y)){    R.d.n = 0;    for(int i = -1;++i<R.n;){    R.d.col[i] = 0;    }Thread t = new Thread(new Runnable(){public void run(){    R.d.solve(-1);}});t.start();start = true;    }}}@Overridepublic void mouseEntered(MouseEvent e) {// TODO 自动生成的方法存根}@Overridepublic void mouseExited(MouseEvent e) {// TODO 自动生成的方法存根}}
⑤ GameBegin.java  main函数在这个文件里
package eq;import java.lang.reflect.InvocationTargetException;public class GameBegin {public static void main(String[] args){try {javax.swing.SwingUtilities.invokeAndWait(new Runnable(){public void run(){              R.sv = new SurfaceView();              R.sv.setVisible(true);}});}catch (InvocationTargetException | InterruptedException e) {// TODO 自动生成的 catch 块e.printStackTrace();}}}
Deal.java  八皇后算法函数都在这一文件里
1. class Position,用于存储一个坐标,分别是 row 行 和 col 列

2. void solve(int beginrow) 从第beginrow行开始往右挪动棋子。如果棋子摆放成功,就进入beginrow+1行。如果棋子到了第8列也摆放不成功,第beginrow行的棋子回第一列,然后进入beginrow-1行。

3. void solve_next() 获取下一个解,只需要把第8行的棋子往右挪一格子

4. boolean check(int r)判断第r行的皇后是不是满足八皇后条件,即横竖斜没有其它皇后,用斜率来判断。

5. void displaycol()用于测试用,与算法无关系。

package eq;class Position{int row;int col;Position(int r,int c){this.row = r;this.col = c;}}public class Deal {int[] col = new int[R.n];int n = 0;public Deal(){}public void solve(int beginrow){int i, j;Position p;//从指定行的下面一行开始往下遍历for(i=beginrow;++i<R.n;){//从当前列开始往后遍历for(j=col[i];j<R.n;j++){R.qp.rd();R.sleep(R.sleeptime);//赋值col[i]=j;//检查该行与前面所有行是否能共存if(check(i)){break;}}//如果当前列遍历到最后if(j >= R.n){//该列的皇后回到第一列col[i]=0;    //往上回溯一行,由于++i所以需要-2i-=2;//上面一行的皇后右移一格,由于-2所以+1if(i+1>=0)col[i+1]++;else i = -1;//如果是第一行最后一列回溯,即完成一个循环}}}public void solve_next(){//获得下一个解。把最后一行的皇后右移,继续遍历即可col[R.n-1]++;solve(R.n-2);R.qp.rd();R.next = true;}boolean check(int r){int i;double k;for(i=r;--i>=0;){k = Math.abs(((double)col[r]-(double)col[i])/((double)r-(double)i));if(k == 1.0 || k == 0.0){return false;}}return true;}void displaycol(){int i;for(i=-1;++i<R.n;){System.out.print(col[i]+1+ ",");}System.out.println();}}

⑦ Input.java  输入窗口,按下菜单栏里的菜单项弹出。

package eq;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import javax.swing.JButton;import javax.swing.JFrame;import javax.swing.JOptionPane;import javax.swing.JTextField;public class Input extends JFrame implements ActionListener {JTextField JTF;Input(){this.setSize(200,120);this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);this.setLayout(null);JTF = new JTextField();JTF.setBounds(10,10,180,25);this.add(JTF);JButton JB = new JButton("确定");JB.addActionListener(this);JB.setBounds(10,50,60,30);this.add(JB);}@Overridepublic void actionPerformed(ActionEvent e) {if(e.getActionCommand().equals("确定")){String[] a = JTF.getText().split(" ");int i;for(i=-1;++i<a.length && i<R.n;){R.d.col[i] = Integer.parseInt(a[i])-1;}R.qp.rd();for(i=0;++i<R.n;){if(!R.d.check(i)){JOptionPane.showMessageDialog(R.sv,"不满足八皇后要求","错误",JOptionPane.ERROR_MESSAGE);break;}}if(i==R.n){JOptionPane.showMessageDialog(R.sv,"满足八皇后要求","正确",JOptionPane.INFORMATION_MESSAGE);}}}}
⑧ BoxText.java  按钮类。一个类变量代表一个按钮。

package eq;import java.awt.Color;import java.awt.Font;import java.awt.FontMetrics;import java.awt.Graphics;import javax.swing.JLabel;public class BoxText{String text = "";String fontface = "";int fonttype = 0;int fontsize = 0;int Box_x = 0;int Box_y = 0;int Box_Height = 0;int Box_Width = 0;public BoxText(String text,String fontface,int fonttype,int fontsize,int Box_x,int Box_y){///////////  1. 获取值:text: 文本; fontface: 字体; fonttype: 字体类型; fontsize: 字体大小  /////////////////////////////            Box_x,Box_y: 按钮左上角顶点所在位置                                                                                          ///////////////////this.text = text;this.fontface = fontface;this.fonttype = fonttype;this.fontsize = fontsize;this.Box_x = Box_x;this.Box_y = Box_y;////////////// 2. 根据字体的高度和宽度,设置箱子的高度和宽度   ///////////////////////Font f = new Font(fontface, fonttype, fontsize);FontMetrics fm = new JLabel().getFontMetrics(f);Box_Height = fm.getHeight() ;Box_Width = fm.stringWidth(text) + 20;}/** * 获取文本左下角顶点的坐标x * @return 文本左下角顶点的坐标x */public int getText_x(){return Box_x + 10;}/** * 获取文本左下角顶点的坐标y * @return 文本左下角顶点的坐标y */public int getText_y(){return Box_y + Box_Height - 5;}/** * 获取面板paint函数中的Graphics来将该箱子画上去 * @param g 某画板的Graphics */public void draw(Graphics g){g.setColor(new Color(0,0,0));g.fillRect(Box_x,Box_y,Box_Width,Box_Height);g.setFont(new Font(fontface,fonttype,fontsize));g.setColor(new Color(255,255,255));g.drawString(text, getText_x(), getText_y());}/** * 看箱子是否被按下 * @param x 鼠标弹起的x坐标 * @param y 鼠标谈起的y坐标 * @return 布尔类型:是否按下 */public boolean isClicked(int x,int y){return x >= Box_x && y >= Box_y && x <= Box_x+Box_Width && y <= Box_y + Box_Height;}}<strong></strong>



算法分析:




本例子的jar文件下载:http://download.csdn.net/detail/u013580497/8902079






0 0
原创粉丝点击