1. 程式人生 > >八數碼難題————Astar演算法好

八數碼難題————Astar演算法好

八數碼難題

//A*演算法 +深搜 
//最優性剪枝有兩個
//第一個是當前一定不是最優解見test
//第二個是當前狀態在以前出現過見pre 
#include <iostream>
#include <cstdio>
using namespace std; 
char s[10];
bool judge;
int sta[4][4],x,y,k=2;
int ans[4][4]={{0,0,0,0},{0,1,2,3},{0,8,0,4},{0,7,6,5}};
//方向設成這樣很有講究
//把左右兩步相加等於3,上下兩步相加等於3
//如果說上一步是向左你這一步向右,或者是上一步向上這一步向下,就回到上次狀態了吧?
//回到上次狀態就重複了直接過濾return
//方便後面check 
int dx[4]={0,1,-1,0};
int dy[4]={1,0,0,-1};
//判當前狀態是否與目標狀態吻合 
bool check(){
	for(int i=1;i<=3;i++)
	for(int j=1;j<=3;j++)
	if(ans[i][j]!=sta[i][j])return 0;
	return 1;
}
//最優性剪枝 
//如果當前狀態和目標狀態的不同點+已經走的步數>列舉的深度就不用走下去 
bool test(int step){
	int diff=0;
	for(int i=1;i<=3;i++)
	for(int j=1;j<=3;j++)
	if(ans[i][j]!=sta[i][j]){
		if(++diff+step>k)return 0; //在迴圈內部判,更好 
	} 
	return 1;
}
//演算法核心
//第一步是看這個步驟到達沒有 
void Astar(int step,int x,int y,int pre){
	if(step==k){
		if(check())judge=1;//這裡不應該把check和step一起形成條件判斷,因為這樣的話到了k步還會一直搜下去 
		return;
	}
	if(judge)return;
	for(int i=0;i<4;i++){//四面廣搜 
		int nx=x+dx[i];
		int ny=y+dy[i];
		if(nx>3||nx<1||ny>3||ny<1||pre+i==3)continue;//這個就是那個判斷有沒有回到上次狀態的請況,簡直大佬! 這個剪枝想不出來60頂天! 
		swap(sta[nx][ny],sta[x][y]);
		if(test(step))Astar(step+1,nx,ny,i);
		swap(sta[nx][ny],sta[x][y]);
	}
}
int main() {
	scanf("%s",&s);
	for(int i=0;i<9;i++){
		sta[i/3+1][i%3+1]=s[i]-'0';
		if(s[i]-'0'==0){x=i/3+1;y=i%3+1;}
	}
	if(check()){
		printf("%d ",0);
		return 0;
	}
	while(++k){
		Astar(0,x,y,-1);
		if(judge){
			printf("%d",k);
			break;
		}
	}
	return 0;
}