八数码之 ①暴力BFS+哈希表版 ②双向BFS+输出最佳方案版

#include <iostream>
#include <stdlib.h>
#include<string.h>
#include<algorithm>
using namespace std;
typedef int state[9];
const int maxstate=1000001;
state goal,st[maxstate];
int dis[maxstate];
int endsteps;
const int dx[]={0,0,1,-1};
const int dy[]={1,-1,0,0};
void init_lookup_table();
int try_to_insert(int);
int bfs(){
	init_lookup_table();
	int front=1,rear=2;
    while(front<rear){
		state &s=st[front];
		if(memcmp(goal,s,sizeof(s))==0){endsteps=front;return front;}
		int z;
		for(z=0;z<9;z++){
			if(!s[z]){break;}
		}
		int x=z/3;
		int y=z%3;
		for(int i=0;i<4;i++){
			int newx=x+dx[i];
			int newy=y+dy[i];
			int newz=newx*3+newy;
		if(newx>=0&&newx<3&&newy>=0&&newy<3){
			state &t=st[rear];
			memcpy(&t,&s,sizeof(s));
			t[newz]=s[z];
			t[z]=s[newz];
			dis[rear]=dis[front]+1;
			if(try_to_insert(rear))rear++;}

		}
		front++;
	}
	return 0;
}
const int hashsize=1000003;
int head[hashsize],Next[maxstate];
void init_lookup_table(){
	memset(head,0,sizeof(head));
}
int Hash(state &s){
	long long sum=0;
	for(int i=0;i<9;i++){
		sum=sum*10+s[i];
	}
	return sum%hashsize;
}
int try_to_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];
	}
	Next[s]=head[h];
	head[h]=s;
	return 1;
}



int main(){
for(int i=0;i<9;i++)cin>>st[1][i];
for(int i=0;i<9;i++)cin>>goal[i];
int ans=bfs();
if(ans>0){
	cout<<dis[ans]<<endl;
		}

else {cout<<"-1"<<endl;}


 system("pause");
  return 0;
}


↑①暴力BFS+哈希表版(可自定义初状态和末状态,自动计算所需要的最短步数,如果无法实现则输出-1)

↓②双向BFS+输出最佳方案版(末状态固定,默认为123456780)(从左到右,从上到下,0代表空格)

注意:输入格式为一个字符串,即一个9位数,空格默认用x表示

如:第一行为123第二行为456第三行为7+空格+8 ,则输入数据应该为   1234567x8

如果不能实现则输出“unsolvable",存在最佳路径时输出要走的所有步数(在源码上优化了一下,本来代码只输出步数)

#include<cstdio>      //双向BFS poj 1077 16ms
 #include<cstring>
#include<queue>
#include<iostream>
 using namespace std;
 const int V=362882;
 struct nod{
     int n,x;   //n表示康拓展开的值,x表示9的位置。
     int m[9];  //记录状态
 };
 int fac[]={0,1,2,6,24,120,720,5040,40320};    //阶乘表
 int dx[]={1,-1,0,0},dy[]={0,0,-1,1},tr[]={1,0,3,2};     //tr用于转向
 char dir[]="dulr";
 int init[3][3];
 int vir[2][V],p[V],fa[V],d[V],re,rs,ko;
 queue<nod> q[2];                     //两个队列
 void bfs(nod st,nod ed);
 int exp(nod s,int k);
 int cato(nod a);
 void output(char s){
	 int x=0,y=0;
	 for(int i=0;i<3;i++){
		 for(int j=0;j<3;j++){
			 if(init[i][j]==0){x=i;y=j;break;}
		 }
	 }
	 switch(s){
	 case 'l':
		 init[x][y]=init[x][y-1];
		 init[x][y-1]=0;
		 break;
	 case 'r':
		 init[x][y]=init[x][y+1];
		 init[x][y+1]=0;
		 break;
	case 'u':
		 init[x][y]=init[x-1][y];
		 init[x-1][y]=0;
		 break;
case 'd':
		 init[x][y]=init[x+1][y];
		 init[x+1][y]=0;
		 break;
	 }
	 for(int i=0;i<3;i++){
		 for(int j=0;j<3;j++){
			 cout<<init[i][j]<<" ";
		 }
		 cout<<endl;
	 }
 }
 int main()
 {
 //    freopen("in.in","r",stdin);
     char str[30]; int i;
     nod st,ed;
     while(gets(str)!=NULL)
     {   

         int cnt=0;
		 init[0][0]=str[0]-'0';
		 init[0][1]=str[1]-'0';
		 init[0][2]=str[2]-'0';
		 init[1][0]=str[3]-'0';
		 init[1][1]=str[4]-'0';
		 init[1][2]=str[5]-'0';
		 init[2][0]=str[6]-'0';
		 init[2][1]=str[7]-'0';
		 init[2][2]=str[8]-'0';
		 for(int i=0;i<3;i++){
			 for(int j=0;j<3;j++){
				 if(init[i][j]=='x'-'0'){init[i][j]=0;
				 break;}
			 }
		 }
		 for(i=0;i<9;i++){
			 st.m[i]=i+1;      }       //读取初始的起点和终点
         for(i=0;i<strlen(str);i++){
             if(str[i]=='x')  ed.x=cnt, ed.m[cnt++]=9;
             if(str[i]>='1'&&str[i]<='8') ed.m[cnt++]=str[i]-'0';
         }
         ed.n=cato(ed);
         st.x=8; st.n=cato(st);
         ko=-1,cnt=0;
         bfs(st,ed);                    //双向BFS搜索
         if(ko!=-1){                   //ko表示是交点的方向,如果没改变说明没交点
             for(i=re;fa[i]!=i;i=fa[i]) d[cnt++]=p[i];        //下面几行打印路径
			 for(i=cnt-1;i>=0;i--) {printf("%c\n",dir[d[i]]);output(dir[d[i]]);}
             printf("%c\n",dir[ko]);output(dir[ko]);
			 for(i=rs;i!=st.n;i=fa[i]) {printf("%c\n",dir[tr[p[i]]]);output(dir[tr[p[i]]]);}
         }
         else printf("unsolvable");
         printf("\n");
     }
     return 0;
 }
 int cato(nod a)        //康拓展开
 {
     int i,j,k,sum=0;
     for(i=0;i<9;i++){
         for(j=i+1,k=0;j<9;j++) if(a.m[j]<a.m[i]) k++;
         sum+=k*fac[8-i];
     }
     return sum;
 }
 void bfs(nod st,nod ed)
 {
     memset(fa,-1,sizeof(fa));
     memset(vir,0,sizeof(vir));
     q[0].push(st); q[1].push(ed);          //起点终点入队
     vir[0][st.n]=1; vir[1][ed.n]=1;
     fa[st.n]=st.n; fa[ed.n]=ed.n;        
     while(!q[0].empty()||!q[1].empty())
     {
         nod ss=q[0].front(); q[0].pop();
         nod ee=q[1].front(); q[1].pop();
         if(exp(ss,0)||exp(ee,1)) break;
     }
 }
 int exp(nod s,int k)              //扩展函数,即对s点寻找下一层的点
 {
     int i,t,sn=s.x,sx=sn/3,sy=sn%3,nn;
     nod nex;
     for(i=0;i<4;i++){
         int nx=sx+dx[i],ny=sy+dy[i];
         if(nx<3&&nx>=0&&ny<3&&ny>=0){
              nex=s;
              nn=nx*3+ny;
              t=nex.m[sn]; nex.m[sn]=nex.m[nn]; nex.m[nn]=t;
              nex.n=cato(nex);         
             nex.x=nn;          //求下一个可能扩展的点
              if(vir[k][nex.n]) continue;
             if(vir[k^1][nex.n]==1) {           //找到交点返回1,k代表是从起点还是从终点的路径
                   if(k) { ko=i; re=s.n; rs=nex.n; }
                   else { ko=tr[i]; re=nex.n; rs=s.n; }
                   return 1;
              }              vir[k][nex.n]=1;
             q[k].push(nex);        //可扩展,入队。
              fa[nex.n]=s.n;
              p[nex.n]=i;
        }
     }
     return 0;
 }


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值