CodeVs 1225 八數碼難題

1225 八數碼難題

Yours和zero在研究A*啓發式算法.拿到一道經典的A*問題,但是他們不會做,請你幫他們.
問題描述

在3×3的棋盤上,擺有八個棋子,每個棋子上標有1至8的某一數字。棋盤中留有一個空格,空格用0來表示。空格周圍的棋子可以移到空格中。要求解的問題是:給出一種初始佈局(初始狀態)和目標佈局(爲了使題目簡單,設目標狀態爲123804765),找到一種最少步驟的移動方法,實現從初始佈局到目標佈局的轉變。

輸入初試狀態,一行九個數字,空格用0表示

只有一行,該行只有一個數字,表示從初始狀態到目標狀態需要的最少移動次數(測試數據中無特殊無法到達目標狀態數據)

283104765

4


這題超經典,值得學搜索的人都去弄一下,可以先用廣搜→雙廣→A*這樣你的搜索就能掌握到方向了。

/*
八數碼難題 
單向bfs+康託展開+hash 
*/
#include<iostream>
#include<cstring>
#include<cstdlib>
using namespace std;
const int dx[5]={0,0,0,1,-1};
const int dy[5]={0,1,-1,0,0};
struct Node
{
	int mp[4][4];
	int step;
};
Node e;
Node d[400005];
int hash[400005];
long fc[10]={1,1,2,6,24,120,720,5040,40320,362880};
long total=0;
long head=0, tail=0;
bool flag=false;
void debug(Node x)
{
	for (int i=1; i<=3; i++)
	{
	 
	   for (int j=1; j<=3; j++)
	   cout<<x.mp[i][j]<<" ";
	   cout<<endl;
   }
   cout<<"##############"<<endl;
}
long KT(Node x)
{
	int m[10];
	int tot=0;
	for (int i=1; i<=3; i++)
	  for (int j=1; j<=3; j++)
	  {
	  	m[++tot]=x.mp[i][j];
	  	//debug(x);
	  }
	long num=1;
	for (int i=1; i<=9; i++)
	  {
	     int temp=0;
	  	 for (int j=i+1; j<=9; j++)
	  	 {
	  	 if (m[i]>m[j]) 
		   {
		     temp++;
		   }
	}
	  
	  	 num+=fc[9-i]*temp;
	  }
	  return num;
	  
}
bool Hash(Node x)
{
	long y=KT(x);
	if(!hash[y]){
		hash[y]=1;
		return true;
	}
	return false;
}
void sp(int &a, int &b)
{
	int t=a;
	a=b;
	b=t;
}
bool pd(int x, int y)
{
	if (x<0 || x>3 ||y<0 ||y>3) return 0;
	else return 1;
}
void move(int x, int y)
{
	for (int i=1; i<=4; i++)
	{
		int xx=dx[i]+x;
		int yy=dy[i]+y;
		if (pd(xx, yy))
		{
			tail++;
			for (int i=1; i<=3; i++)
			  for (int j=1; j<=3; j++)
			   d[tail].mp[i][j]=d[head].mp[i][j];
			   sp(d[tail].mp[x][y], d[tail].mp[xx][yy]);
			   if (Hash(d[tail])) {
			   	d[tail].step=d[head].step+1;
			   //	debug(d[tail]);
			   	if (hash[total]) 
				   {
			   	       flag=true;
			   	        return ;
				   }
			   }
			   else tail--;
		}
	}
}
void bfs()
{
     while (head<=tail)
     {
     	  for (int i=1; i<=3; i++)
     	    for (int j=1; j<=3; j++)
     	    {
     	    if (!d[head].mp[i][j]) 
			   {
			      move(i, j);  
			      if (flag) 
				  {
     	    	       cout<<d[tail].step<<endl;
     	    	       return;
     	          }	
				  break;
     	       }
            }
	 head++;
    }
}

void init()
{
	d[0].mp[1][1]=1; d[0].mp[1][2]=2; d[0].mp[1][3]=3;
	d[0].mp[2][1]=8; d[0].mp[2][2]=0; d[0].mp[2][3]=4;
	d[0].mp[3][1]=7; d[0].mp[3][2]=6; d[0].mp[3][3]=5;
	d[0].step=0;
}
int main()
{
	memset(hash, 0, sizeof(hash));
	init();
	for  (int i=1; i<=3; i++)
	 for (int j=1; j<=3; j++)
	 {
	 	char s;
	 	cin>>s;
	 	e.mp[i][j]=s-'0';
	 }
	total=KT(e); 
	Hash(d[0]);
	bfs();
	return 0;
}

/*
八數碼難題 雙向bfs+hash+cantor 參考了hzwer大犇的代碼,寫的真不錯
*/
#include<iostream>
#include<cstdlib>
#include<cstring>
using namespace std;
const int dx[5]={0,0,0,1,-1};
const int dy[5]={0,1,-1,0,0};
struct Node{
	int mp[4][4];
};
Node d[2][400000];//0代表正向bfs, 1代表反向bfs ;
long fc[10]={1,1,2,6,24,120,720,5040,40320,362880};
int hash[2][400000];//hash判重+存儲step
int step[2][400000]={0,0};
long head[2], tail[2]={1,1}; 
bool flag=0;
void debug1(int k, int temp)
{
	cout<<temp<<"--------temp"<<endl;
	cout<<k<<"---------bfs方向"<<endl;
	cout<<hash[k][temp]<<endl;
	cout<<"hash----------------"<<endl;
}
void debug(int b[4][4])
{
	for (int i=1; i<=3; i++)
	  {
	  	for (int j=1; j<=3; j++)
	  	cout<<b[i][j]<<" ";
	  	cout<<endl;
	  }
	  cout<<"#####################"<<endl;
}
long KT(int b[4][4])
{
	int m[10];
	int tot=0;
	for (int i=1; i<=3; i++)
	  for (int j=1; j<=3; j++)
	  {
	  	m[++tot]=b[i][j];
	  }
	long num=1; 
	for (int i=1; i<=9; i++) 
	{
		int temp=0;
		for (int j=i+1; j<=9; j++)
		if (m[i]>m[j]) temp++;
		num+=fc[9-i]*temp;
	}
	return num;
}
void sp(int &a, int &b)
{
	int t=a;
	a=b;
	b=t;
}
bool pd(int x, int y)
{
	if (x<0 || x>3 || y<0 || y>3) return 0;
	else return 1;
}
void bfs(int k)
{
	int x=0, y=0;
	for (int i=1; i<=3; i++)
	 for (int j=1; j<=3; j++)
	 {
	 	if (d[k][head[k]].mp[i][j]==0) 
	 	{
	 		x=i;
	 		y=j;
	 		break;
	 	}
	 }
	 for (int i=1; i<=4; i++)
	 {
	 	int xx=dx[i]+x;
	 	int yy=dy[i]+y;
	 	if (pd(xx, yy))
	 	{
	 		for (int i=1; i<=3; i++)
	 		  for (int j=1; j<=3; j++)
	 		  d[k][tail[k]].mp[i][j]=d[k][head[k]].mp[i][j];
	 		  sp(d[k][tail[k]].mp[x][y], d[k][tail[k]].mp[xx][yy]);
	 		  int temp=KT(d[k][tail[k]].mp);
	 		  if (hash[k][temp]==-1)
	 		  {
	 		  	step[k][tail[k]]=step[k][head[k]]+1;
	 		  	hash[k][temp]=step[k][tail[k]];
	 		  	if(hash[0][temp]!=-1 && hash[1][temp]!=-1)
	 		  	{
	 		  		//cout<<d[k][tail[k]].step<<"  "<<d[1-k][tail[k]-20].step<<endl;
	 		  		cout<<hash[0][temp]+hash[1][temp]<<endl;
	 		  		flag=1;
	 		  		return ;
	 		  	}
	 		  }  
			  // cout<<tail[k]<<endl;
			   //debug(d[k][tail[k]].mp);
	 		  tail[k]++;
	 		 
	 	}
	 }
	 head[k]++;
}
void search()
{
	while (!flag)
	{
		if (tail[0]-head[0]<=tail[1]-head[1]) bfs(0);
		else bfs(1);
	}
}
void init(int b[10])
{
	d[0][0].mp[1][1]=1; d[0][0].mp[1][2]=2; d[0][0].mp[1][3]=3;
	d[0][0].mp[2][1]=8; d[0][0].mp[2][2]=0; d[0][0].mp[2][3]=4;
	d[0][0].mp[3][1]=7; d[0][0].mp[3][2]=6; d[0][0].mp[3][3]=5;
	int tot=0;
	for (int i=1; i<=3; i++)   for (int j=1; j<=3; j++)   d[1][0].mp[i][j]=b[++tot];
//	debug(d[0][0].mp);
	hash[0][KT(d[0][0].mp)]=hash[1][KT(d[1][0].mp)]=0; 
//	debug1(1, KT(d[1][0].mp));
}
int main()
{
	memset(hash, -1, sizeof(hash));
	int b[10];
	string a;
	cin>>a;
	for (int i=0; i<a.size(); i++)
	{
		b[i+1]=a[i]-'0';
	}
	init(b);
	search();
	return 0;
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章