2018.10.2模拟赛

  1. 八数码
    1 问题描述
    有33 共9 个格子,其中有一个格子是空的,其他格子填满了18 之间不同的数字。通过
    移动格子可以改变数字和空格的位置,现在给你初状态和末状态,请你给出最少的移动步数。
    2 输入格式
    输入文件名为 eight. in。
    给出6 行,每行有3 个数,每两个数用一个空格空开,每个数在08 之间,其中0 表示空
    格。
    前3 行表示初始状态,后3 行表示目标状态。
    3 输出格式
    输出文件名为eight.out。
    输出一行一个数,表示从初始状态移动到目标状态的最少步数。
    如果无解则输出?1。
    4 样例
    见下发/eight/eight.in(out)。
    样例解释见下发/eight/eight.jpg。

这道题还是一道挺经典的广搜,再用点康托展开或者map的判重
具体看代码

#include<bits/stdc++.h>
using namespace std;
int dx[4]={-1,1,0,0},dy[4]={0,0,-1,1};
int a[500000][4][4],b[4][4],ai,aj,f[400000],o[10],fx[400000],fy[400000],c[10][10],ha;
map<int,bool> mp;
int main()
{
    freopen("eight.in","r",stdin);
	freopen("eight.out","w",stdout); 
	int ss=0;
	for (int i=1; i<=3; i++)
	  for (int j=1; j<=3; j++)
	    {
	      scanf("%d",&a[1][i][j]);
	      ss=ss*10+a[1][i][j];
	      if (a[1][i][j]==0) {ai=i; aj=j;}
	    }//读入初始状况,记录0的位置 
    mp[ss]=true;   
	for (int i=1; i<=3; i++)
	  for (int j=1; j<=3; j++)
	      scanf("%d",&b[i][j]);//终点 
   int h=0,t=1;
   fx[t]=ai,fy[t]=aj;//广搜,0的位置入队 
   while (h<=t)
     {
   	    h++;
   	    bool pp;
   	    for (int k=0; k<4; k++)
		   {
		   	  int x=fx[h]+dx[k],y=fy[h]+dy[k];//四个方向拓展 
		   	  if (x<1||y<1||x>3||y>3) continue;
		   	  for (int l=1; l<=3; l++)
		   	    for (int p=1; p<=3; p++)
		   	      c[l][p]=a[h][l][p];//记录一个数组用来判断新的这种移动是否合法 
		   	  int u=c[x][y];
		   	  c[x][y]=c[fx[h]][fy[h]];
		   	  c[fx[h]][fy[h]]=u;//移动等于交换0和它相邻的某个数字 
		   	  int s=0;
		   	  for (int l=1; l<=3; l++)
		   	    for (int p=1; p<=3; p++)
		   	      s=s*10+c[l][p];//把数组压成十进制 ,容易判重 
			  if (mp[s]==false)//map判重 
		   	    {
		   	    	mp[s]=true;
		   	    	t++;
		   	    	fx[t]=x,fy[t]=y;
		   	    	f[t]=f[h]+1;//记录移动次数 
		   	    	pp=false;
		   	    	for (int l=1; l<=3; l++)
		   	          for (int p=1; p<=3; p++)
		   	            {
		   	              a[t][l][p]=c[l][p];
		   	              if (a[t][l][p]!=b[l][p]) pp=true;
		   	            }//如果合法那么就是新状态,每次和终点比较一下,如果成立就可以 
		   	        if (pp==false) {cout<<f[t]; return 0;}
		   	    }
	       }
     }
    cout<<"-1";
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值