十五数码之宽度优先搜索
来源:互联网 发布:dev-c 软件下载 编辑:程序博客网 时间:2024/05/21 17:58
在用宽度优先搜索写了八数码之后,又想着写一下15数码,在八数码的基础上做了一些更改,比如字符数组的截取,还有内存的大小更改,但是还是不尽人意,给大家看看吧,希望大家能给些意见,准备用A星算法重新写一下十五数码,看看有什么效果。。。。
算法部分:
import java.util.*;public class Fifteennumberpath { final static int dx[] = {-1, 1, 0, 0}; final static int dy[] = { 0, 0,-1, 1}; final static String dir = "UDLR"; static int maxstate =40000000; static int [][]st = new int[maxstate][16]; static int []goal = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,0}; static int []dist = new int[maxstate]; static int []fa = new int[maxstate]; static int []move = new int[maxstate]; static boolean []vis = new boolean[maxstate]; static int []fact = new int[16]; static StringBuffer path; public static boolean isok(int []a) //判断数组中的逆序数,如果为偶数返回true,否则返回false; { int sum=0; for(int i=0; i < 16; i++) for(int j=i+1; j < 16; j++) if(a[j] != 0 && a[i] != 0 && a[i] > a[j]) sum++; if(sum % 2 == 0) { return true; } return false; } private static void init_lookup_table()//将数组fact初始化为1,1,2,6,24,120,720,5080,40640 { fact[0] = 1; for(int i = 1; i < 16; i++) { fact[i] = fact[i-1] * i; } Arrays.fill(vis, false);//将数组fill中的元素全部用FALSE来填充,也是一个初始化 } private static boolean try_to_insert(int s) { int code = 0; for(int i = 0; i < 16; i++) { int cnt = 0; for(int j = i+1; j < 16; j++) { if(st[s][j] < st[s][i]) { cnt++;//判断逆序数的数量,从S行的第一个元素到最后一个元素分别比较, } } code += fact[15-i] * cnt;//S行的第一个元素与fact数组第一个的积的和相加,交叉积之和 } if(vis[code]) { return false;//判断vis[code]的值为真的话返回FALSE } return vis[code] = true;//判断vis[code]的值不为真的话返回true } private static void print_path(int cur) { while(cur != 1) { path.insert(0,dir.charAt(move[cur]));//在索引0的位置插入UDRL中一个,由输入的cur来决定 cur = fa[cur];//然后给cur赋值fa数组中索引0的数 } } private static int bfs() { //宽度优先搜索 init_lookup_table(); //将数组fact初始化为1,1,2,6,24,120,720,5080,40640 int front = 1 , rear = 2; try_to_insert(front);//判断st[front][]这一行中对应的逆序数和 while(front < rear) { if(Arrays.equals(st[front], goal)) //如果st[front]这一行与goal相等,返回front { return front; } int z; for(z = 0; z < 16; z++) { if(st[front][z] == 0) { break;//当st[front]中出现某个元素为0,跳出,z标记为开始为0的下标 } } int x = z/4, y = z%4; for(int d = 0; d < 4; d++) { int newx = x + dx[d]; int newy = y + dy[d]; int newz = newx * 4 + newy; if(newx >= 0 && newx < 4&& newy >= 0 && newy < 4) { st[rear] = Arrays.copyOf(st[front], st[front].length); st[rear][newz] = st[front][z]; st[rear][z] = st[front][newz]; dist[rear] = dist[front] + 1; if(try_to_insert(rear)) { fa[rear] = front; move[rear] = d; rear++; } } } front++; } return 0; } public static String solve(String state[]) { path = new StringBuffer(); for(int i = 0; i < state.length; i++) { st[1][i] = Integer.valueOf(state[i]); System.out.println(state[i]); } int ans = bfs(); print_path(ans); return path.toString(); }}
UI界面部分:
import java.awt.*;import javax.swing.*;import java.awt.event.*;import java.nio.file.Path;import java.util.*; public class FifteennumberFram extends Frame implements ActionListener,KeyListener{ MenuBar menubar=new MenuBar();//创建新的菜单栏 //Menu menu_file = new Menu("文件(F)");//创建下拉菜单文件 //Menu menu_file1 = new Menu("文件(F)"); Button restart = new Button("随机打乱");//在下拉菜单中设置选项 Button nextPath = new Button("提示"); Button printPath = new Button("开始"); Button exit = new Button("退出程序"); Button[] button;//创建按钮 Panel panel;//创建面板panel Panel panel1; int row,col;//设置行数和列数 private static int position,cellNum;//用来保存位置和行列乘积数量的变量 final int dr[] = { 0,-1, 0, 1}; final int dc[] = {-1, 0, 1, 0}; public FifteennumberFram(int row,int col) { super.setMenuBar(menubar);//Windows风格 try { UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); } catch (Exception e) { e.printStackTrace(); } this.row = row; this.col = col; cellNum = row*col; restart.addActionListener(this); exit.addActionListener(this); nextPath.addActionListener(this); printPath.addActionListener(this); //menu_file.add(restart);//将选项添加到菜单中 //menu_file1.add(restart); //menu_file.add(printPath); //menu_file.add(nextPath); //menu_file.add(exit); //menubar.add(menu_file);//将菜单添加到菜单栏中 panel = new Panel(new GridLayout(row,col)) ; panel1 = new Panel(new GridLayout(1,4)) ; panel1.add(restart); panel1.add(nextPath); panel1.add(printPath); panel1.add(exit); button = new Button[cellNum];//创建按钮数目,9个 for(int i = 0; i < cellNum; i++) { if(i == cellNum - 1) {//初始化按钮上的数字 button[i] = new Button(" ");//最后一个为空 }else { button[i] = new Button(String.valueOf(i + 1));//其他按钮为对应的数字 } /*button[0]=new Button("1"); button[1]=new Button("2"); button[2]=new Button("3"); button[3]=new Button("8"); button[4]=new Button(" "); button[5]=new Button("4"); button[6]=new Button("7"); button[7]=new Button("6"); button[8]=new Button("5");*/ button[i].setFont(new Font("宋体", 1, 20));//设置按钮上显示的数字的字体 button[i].addActionListener(this);//添加监听 button[i].addKeyListener(this);//添加响应 panel.add(button[i]);//在面板上添加按钮 } position = cellNum - 1; this.add(BorderLayout.NORTH,panel1); this.add(BorderLayout.CENTER,panel);//面板排列方式 this.setTitle("十五数码");//文件设置标题 this.setVisible(true);//可显示,必须 this.setSize(300,300);//设置页面的大小 Toolkit kit = Toolkit.getDefaultToolkit(); Dimension screenSize = kit.getScreenSize(); int screenWidth = screenSize.width/2; int screenHeight = screenSize.height/2; int height = this.getHeight(); int width = this.getWidth(); this.setLocation(screenWidth-width/2, screenHeight-height/2); this.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); } void start()//对于按钮上的数字进行随机排列 { int a[] = new int[16]; do { int k = 0; Random random=new Random(); //调用这个Math.Random()函数能够返回带正号的double值,该值大于等于0.0且小于1.0 Set set=new HashSet();//不允许出现重复元素 while(set.size() < cellNum-1) { int n=random.nextInt(cellNum-1)+1; //保证产生的随机数在1-15之间,且不重复,写入set集合中 if(!set.contains(n)) { set.add(n); a[k++] = n; } } a[k] = 0; }while(!Fifteennumberpath.isok(a)); for(int i = 0; i < 16; i++) button[i].setLabel(String.valueOf(a[i])); button[cellNum-1].setLabel(" "); position = cellNum - 1; } boolean win() { for(int i = 0; i < cellNum - 1; i++) { if(button[i].getLabel().equals(" "))//获取每一个按钮的值,如果为空,返回false { return false; } else if(Integer.valueOf(button[i].getLabel()) != i+1) //如果对应的按钮与初始化的时候不一致,也返回false { return false; } /*if(Integer.valueOf(button[0].getLabel()) !=1) return false; else if(Integer.valueOf(button[1].getLabel()) !=2) return false; else if(Integer.valueOf(button[2].getLabel()) !=3) return false; else if(Integer.valueOf(button[3].getLabel()) !=8) return false; else if(Integer.valueOf(button[5].getLabel()) !=4) return false; else if(Integer.valueOf(button[6].getLabel()) !=7) return false; else if(Integer.valueOf(button[7].getLabel()) !=6) return false; else if(Integer.valueOf(button[8].getLabel()) !=5) return false; else if(button[4].getLabel().equals(" ")) return false;*/ } return true;//要是与设定的对应的话返回true } private boolean judge(Button a, Button b) //判断按钮a和b之间的位置关系,相邻的话返回true,否则返回false //(dr,dc)=(0,-1)代表a在b的下方 //(dr,dc)=(-1,0)代表a在b的左方 //(dr,dc)=(0,1)代表a在b的上方 //(dr,dc)=(1,1)代表a在b的右方 { for(int i = 0; i < 4; i++) { if((a.getX()==b.getX()+dr[i]*a.getWidth())&&(a.getY()==b.getY()+dc[i]*a.getHeight())) { return true; } } return false; } public void actionPerformed(ActionEvent e) { String[] state = new String[cellNum]; if(e.getSource() == restart) { start(); return; } else if(e.getSource() == exit) { System.exit(0); return; } else if(e.getSource() == nextPath) { for(int i = 0; i < cellNum; i++) { if(button[i].getLabel().equals(" ")) { state[i]="0"; } else { state[i]=button[i].getLabel(); } } System.out.println(state); String path = Fifteennumberpath.solve(state); //调用写的bfs算法 JOptionPane.showMessageDialog(this,"建议走:"+path+" 一共"+path.length()+"步!"); return; } else if(e.getSource() == printPath) { for(int i = 0; i < cellNum; i++) { if(button[i].getLabel().equals(" ")) { state[i]="0"; } else { state[i]=button[i].getLabel(); } } String path = Fifteennumberpath.solve(state); for(int i = 0; i < path.length(); i++) { switch(path.charAt(i)) { case 'U': go(KeyEvent.VK_UP); break; case 'D': go(KeyEvent.VK_DOWN); break; case 'L': go(KeyEvent.VK_LEFT); break; case 'R': go(KeyEvent.VK_RIGHT); break; } try { Thread.sleep(500); } catch (InterruptedException e1) { e1.printStackTrace(); } } } for(int i = 0; i < cellNum; i++) { if(e.getSource() == button[i]) { if(!button[i].getLabel().equals(" ") && judge(button[i],button[position])) { button[position].setLabel(button[i].getLabel()); button[i].setLabel(" "); position = i; } } } if(win()) { JOptionPane.showMessageDialog(this,"Congratulations"); } } void go(int dir) { int x = position / col; int y = position % col; switch(dir) { case KeyEvent.VK_UP: if(x != 0) { button[position].setLabel(button[position-col].getLabel()); button[position-col].setLabel(" "); position -= col; } break; case KeyEvent.VK_DOWN: if(x != row-1) { button[position].setLabel(button[position+col].getLabel()); button[position+col].setLabel(" "); position += col; } break; case KeyEvent.VK_LEFT: if(y != 0) { button[position].setLabel(button[position-1].getLabel()); button[position-1].setLabel(" "); position -= 1; } break; case KeyEvent.VK_RIGHT: if(y != col-1) { button[position].setLabel(button[position+1].getLabel()); button[position+1].setLabel(" "); position += 1; } break; } } public void keyPressed(KeyEvent e) { go(e.getKeyCode()); if(win()) { JOptionPane.showMessageDialog(this,"Congratulations"); //JOptionPane.showMessageDialog(this,this.nextPath); } } public void keyReleased(KeyEvent e) {} public void keyTyped(KeyEvent e) {} public static void main(String[] args) { new FifteennumberFram(4, 4); }}
1 0
- 十五数码之宽度优先搜索
- 【Java】八数码的宽度优先搜索算法及用户界面
- 八数码宽度优先算法
- 期末复习之宽度优先搜索
- 宽度优先搜索 BFS
- 宽度优先搜索BFS
- 宽度优先搜索
- 宽度优先搜索图
- 宽度优先搜索
- 宽度优先搜索
- 宽度优先搜索
- 宽度优先搜索bfs
- 宽度优先搜索
- 宽度优先搜索算法
- 宽度优先搜索
- 宽度优先搜索
- 宽度优先搜索套路
- 宽度优先搜索
- ConcurrentHashMap源码分析
- Android微信(支付)踩坑全记录
- 关于Glide的理解.
- mysql 性能优化方向
- 【Oracle】PL/SQL——异常错误处理
- 十五数码之宽度优先搜索
- 21:三角形最佳路径问题
- hirbnate添加异常第一弹
- 分布式消息队列RocketMQ源码分析之1 -- Topic路由数据结构解析 -- topicRoute与topicPublishInfo与queueId
- docker中安装nginx服务
- 并查集
- 深度学习教程 TensorFlow and Deep Learning Tutorials
- 模型融合
- JDK8中的永久代