八数码问题<set的使用>bfs

the reason of failure:1、如何对0进行上下左右移动

用pos找到0在数组中的下标

可以定义dr[]={0,1,0,-1};dc[]={1,0,-1,0}.然后一个for4次的循环,r=pos/3+dr c=pos%3+dc

便能实现上下左右的移动

2、对于储存状态与查找,可以把数组存入set然后查找。

题意

八数码问题。编号为1~8的8个正方形滑块被摆成3行3列(有一个格子留空),如图7-
14所示。每次可以把与空格相邻的滑块(有公共边才算相邻)移到空格中,而它原来的位置
就成为了新的空格。给定初始局面和目标局面(用0表示空格),你的任务是计算出最少的
移动步数。如果无法到达目标局面,则输出-1。
图7-14 八数码问题举例


代码:

#include <iostream> 
#include <queue>
#include <string.h>
#include <set>
using namespace std;
struct ttt{
	int t;
	int a[9];
};

int str2[9];
int dr[]={1,0,-1,0};
int dc[]={0,1,0,-1};

int main(){
	set<int>vis;
	freopen("in.txt","r",stdin);
	queue<ttt>qq;
 int n,r,c;
 int i,j,k,l,pos1,t1;
 ttt str1,str4,str3;
 cin >> n;
 for(i=0;i<n;i++){
 	for(j=0;j<9;j++)
 		cin >> str1.a[j];
 		  for(j=0;j<9;j++)
 		  	cin >> str2[j];
 		str1.t=0;
 		qq.push(str1);
 		int t1=0;
 		while(!qq.empty()){
 			t1++;
 			str3=qq.front();qq.pop();
 			if(memcmp(str3.a,str2,sizeof(str2))==0){
			 break;} 
		
 			for(j=0;j<9;j++){
 				if(str3.a[j]==0){
 				pos1=j;
 				break;
 			}
			 }
			 str3.t++;
 			for(j=0;j<4;j++){
 				r=pos1/3+dr[j];
 				c=pos1%3+dc[j];
				 memcpy(&str4,&str3,sizeof(str3));
 				if(r>=0&&r<3&&c<3&&c>=0){
 					str4.a[pos1]=str3.a[r*3+c];
 					str4.a[r*3+c]=0;
 					int g=0;
 					for(k=0;k<9;k++){
 						g=g*10+str4.a[k];
					 }
		//			 cout << g << endl;
 					if(!vis.count(g)){
					 vis.insert(g);
					 qq.push(str4);}
				 }
			 }
 		 }
		 if(memcmp(str3.a,str2,sizeof(str2))==0)
		 cout << str3.t << endl;
		 else
		 cout << "-1" << endl;
 }
 return 0;
}

2、用hash判重。

the reason of failure :1、hash需要把所有值都放入st[]这样一个大数组中才能找到之前是否存在里面,hash的mod尽量找一个大的素数。

2、关于memcmp与memcpy都是需要sizeof(a)写大小的。

代码:

#include <iostream>
#include <queue>
#include <string.h>
using namespace std;

struct ttt{
	int a[9],t;
};
const int hashsize =1000003;
typedef int con[9];
int head[5000000];
int next[5000000];
con st[50000000];

int dr[]={0,1,-1,0};
int dc[]={1,0,0,-1};

int aa;
ttt str1,str3,str4;
int str2[9];

int hash(con str5){
	int t1=0;
	for(int g=0;g<9;g++)t1=t1*10+str5[g];
//	cout << "t1=" << t1 << endl;
	return t1%hashsize;
}

int try_insert(int s){
	int h=hash(st[s]);
	int u=head[h];
	while(u){
		if(memcmp(st[u],st[s],sizeof(st[s]))==0)return 0;
		u=next[u];
	}
	head[h]=s;
	next[s]=u;
	return 1;
}

int main(){
	memset(head,0,sizeof(head));
	freopen("in.txt","r",stdin);
	queue<ttt>qq;
	int i,j,k,l;
	int r,c,pos1;
	long long g=1;
	for(i=0;i<9;i++)
		cin >> str1.a[i];
		for(i=0;i<9;i++)
			cin >> str2[i];
		str1.t=0;
		qq.push(str1);
		while(!qq.empty()){
			str3=qq.front();
			qq.pop();
			if(memcmp(str3.a,str2,sizeof(str2))==0)break;
			for(i=0;i<9;i++){
				if(str3.a[i]==0){
				pos1=i;
				break;}
			}
			str3.t++;
		for(i=0;i<4;i++){
			r=pos1/3+dr[i];
			c=pos1%3+dc[i];
			if(r>=0&&r<3&&c>=0&&c<3){
				str4=str3;
				str4.a[pos1]=str3.a[r*3+c];
				str4.a[r*3+c]=0;
				memcpy(st[g],str4.a,sizeof(st[g]));
				if(try_insert(g)){
					qq.push(str4);
					g++;
				}
			}
			
		}
		}
		if(memcmp(str3.a,str2,sizeof(str2))==0)
		cout << str3.t << endl;
		else
		cout << "-1" << endl;
		return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值