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;
}



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值