洛谷 P1379 八数码难题

题目描述

3×3 的棋盘上,摆有八个棋子,每个棋子上标有 1 8 的某一数字。棋盘中留有一个空格,空格用 0 来表示。空格周围的棋子可以移到空格中。要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为 123804765 ),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变。

输入输出格式

输入格式:

输入初始状态,一行九个数字,空格用 0 表示

输出格式:

只有一行,该行只有一个数字,表示从初始状态到目标状态需要的最少移动次数(测试数据中无特殊无法到达目标状态数据)

输入输出样例

输入样例#1:

283104765

输出样例#1:

4

solution

  • 求的是最小步数,属于最优解问题于是就可以搜索了

  • 因为知道末状态,所以可以双向bfs

  • 但我感觉那个太难写了..所以我们来写A*吧

  • 估价函数是当前状态的所有数字的位置对应他们的末状态的位置的曼哈顿距离之和

  • 也就是Guess=i=19(abs(aimx[i]nowx[i])+abs(aimy[i]nowy[i]))

    • aim 表示目标状态, now 表示当前状态, i <script type="math/tex" id="MathJax-Element-135">i</script> 表示的是数字

    • code

      #include<cstdio>
      #include<algorithm>
      using namespace std;
      const int dx[4]={0,0,1,-1},dy[4]={1,-1,0,0};
      const int aimx[10]={1,0,0,0,1,2,2,2,1};
      const int aimy[10]={1,0,1,2,2,2,1,0,0};
      int sta[3][3],Step,px,py,nowx[10],nowy[10];
      bool flag;
      int Guess() {
          int sum=0;
          for(int i=0;i<3;i++)
              for(int j=0;j<3;j++)
                  nowx[sta[i][j]]=i,nowy[sta[i][j]]=j;
          for(int i=1;i<9;i++)
                  sum+=(abs(aimx[i]-nowx[i])+abs(aimy[i]-nowy[i]));
          return sum;
      }
      void Astar(int nowstep,int Step,int px,int py) {
          if(flag||nowstep>Step) return;
          int H=Guess();
          if(H==0) {flag=true;return;}
          if(H+nowstep>Step) return;
          for(int i=0;i<4;i++) {
              int x=px+dx[i],y=py+dy[i];
              if(x<0||y<0||x>2||y>2) continue;
              swap(sta[x][y],sta[px][py]);
              Astar(nowstep+1,Step,x,y);
              swap(sta[x][y],sta[px][py]);
          }
          return;
      }
      int main() {
          for(int i=0;i<3;i++)
              for(int j=0;j<3;j++) {
                  char c;
                  scanf("%c",&c);
                  sta[i][j]=c-'0';
                  if(sta[i][j]==0) px=i,py=j;
              }
          while(!flag) Step++,Astar(0,Step,px,py);
          printf("%d",Step);
          return 0;
      }
      
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值