八數碼難題————Astar演算法好
阿新 • • 發佈:2018-12-19
//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; }