1. 程式人生 > >八數碼問題bfs暴力破解(java實現)

八數碼問題bfs暴力破解(java實現)


八數碼問題

八數碼問題也稱為九宮問題。在3×3的棋盤,擺有八個棋子,每個棋子上標有1至8的某一數字,不同棋子上標的數字不相同。棋盤上還有一個空格,與空格相鄰的棋子可以移到空格中。要求解決的問題是:給出一個初始狀態和一個目標狀態,找出一種從初始轉變成目標狀態的移動棋子步數最少的移動步驟。所謂問題的一個狀態就是棋子在棋盤上的一種擺法。棋子移動後,狀態就會發生改變。解八數碼問題實際上就是找出從初始狀態到達目標狀態所經過的一系列中間過渡狀態。

import java.util.Arrays;


public class Test {	
	public static int MAXSTATE = 1000000;
	
	static class state{//狀態類,這個類的每個物件儲存一種狀態
		int[] state = new int[9];
		public state(int[] state) {
			this.state = state;
		}		
	}
	
	static state[] st = new state[MAXSTATE];//狀態陣列
	static state goal;//目標狀態	
	static int[] dist = new int[MAXSTATE];//距離陣列
	
	static int[] dx = {-1,1,0,0};
	static int[] dy = {0,0,-1,1};
	
	
	static int front = 1,rear=2;
	
	static int bfs(){
		init_lookup_table();		
		while(front < rear){
			state s = st[front];
			if(Arrays.equals(s.state,goal.state)){//如果當前狀態跟目標狀態相同				
				return front;//返回當前指標				
			}
			
			int z;
			for(z=0;z<9;z++){if(0==s.state[z]){break;}}//找出當前狀態0的位置
			int x = z/3;
			int y=z%3; //獲取行列號(0-2)
			
			for(int d=0;d<4;d++){	
				System.out.println("進入方位迴圈");
				int newx = x + dx[d];//移動目標的橫座標
				int newy = y + dy[d];//移動目標的縱座標
				int newz = newx*3 + newy;//移動目標在下一狀態的位置
				if(newx>=0 && newx<3 && newy>=0 && newy<3){//如果移動合法
					System.out.println("移動合法"+newx+"||"+newy);
					int[] temp = Arrays.copyOf(s.state, 9);
					st[rear] = new state(temp);				
					st[rear].state[newz] = s.state[z];
					st[rear].state[z] = s.state[newz];					
					dist[rear] = dist[front]+1;
					System.out.println("在第"+dist[rear]+"層");
					if(try_to_insert(st[rear])){ 						
						rear++;
					}
				}else{
					System.out.println("移動不合法"+newx+"||"+newy);
				}
			}		
			System.out.println(front+"--------------------------");
			front++;
		}		
		return 0;
	}
	
	/*
	static boolean try_to_insert(state t){		
		for(int i=1;i<rear;i++){		
			if(Arrays.equals(t.state, st[i].state)){
				return false;
			}
		}
		return true;
	}
	*/
	static boolean[] vis = new boolean[362880];
	static int[] fact = new int[9];
	
	
	static boolean try_to_insert(state t){		
		int code = 0;
		for(int i=0;i<9;i++){			
			int cnt=0;
			for(int j=i+1;j<9;j++){
				if(t.state[j]<t.state[i]) cnt++;
			}
			code += fact[8-i] * cnt;					
		}
		if(vis[code]){
			return false;
		}else{
			vis[code] = true;
			return true;
		}
	}	
	
	
	static void init_lookup_table(){
		fact[0] = 1;
		for(int i=1;i<9;i++) fact[i] = fact[i-1]*i;
	}
	
	public static void main(String[] args) {
		dist[1] = 0;
		st[1] = new state(new int[]{2,6,4,1,3,7,0,5,8});
		goal = new state(new int[]{8,1,5,7,3,6,4,0,2});
		System.out.println("移動了"+dist[bfs()]+"步");
	}
}