UVA-1604 立体八数码问题 题解答案代码 算法竞赛入门经典第二版

GitHub - jzplp/aoapc-UVA-Answer: 算法竞赛入门经典 例题和习题答案 刘汝佳 第二版

一个立方体只有三个颜色,因此用三个面的位置就可以表示单个立方目前的位置。

每个立方体初始的位置是固定的,变化的是空出来的位置。但是目标只是要求顶面的颜色,没有要求立方体的确切位置。

每次转动时,颜色变化是有规律的,按照方向的不同会变化,这个规律在stepChange中表示。

一开始我使用迭代加深搜索方法去解决。结果正确,但一直超时。我看网上其它人有使用这个方法可以AC的,但我这里就不行(剪枝思路是一样的),可能是它们代码具体操作优化的比较好。

我又看其它方法,我看有人用的是DFS+剪枝,想到使用迭代加深搜索,到第n次遍历时,会与n-1次走的路,计算过程是相同的,因此迭代加深搜索实际上只有当前最后一层是有用的(但迭代加深搜索可以做出来的题目中,很多也确实是这样)。而且这个题目限制了最长步数30次,因此改成DFS试了一下,结果可以AC了。但是也接近3秒,属于比较极限了。

AC代码

cpp 复制代码
#include <stdio.h>

// 目标状态
int goal[3][3];
// 当前空白位置
int emptyPos[2];
// 当前状态
// stateArr[i][j]为一个立方体的状态 最后一个下标的值表示顶面/上面/右侧面三个颜色值
int stateArr[3][3][3];

int minStep = 31;

// 四个方向移动
int steps[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
// 四个方向的反向 改回去使用
int stepsRe[4] = {1, 0, 3, 2};
// 四个方向的原值如何覆盖为新值的对应关系
int stepChange[4][3] = {
    {1, 0, 2},
    {1, 0, 2},
    {2, 1, 0},
    {2, 1, 0}};

// 判断当前状态是否符合终点状态 0表示符合
int judge()
{
  int n = 0;
  int i, j;
  for (i = 0; i < 3; ++i)
  {
    for (j = 0; j < 3; ++j)
    {
      if (goal[i][j] != stateArr[i][j][0])
        return ++n;
    }
  }
  return n;
}

void dfs(int step, int preStep)
{
  if (step >= minStep)
    return;
  int jnum = judge();
  if (jnum == 0)
  {
    minStep = step;
    return;
  }
  // step + 1 + jnum - 1
  if (step + jnum > 30)
    return;

  int preA = emptyPos[0], preB = emptyPos[1];
  int i, j, k, a, b;
  // 四个方向遍历
  for (i = 0; i < 4; ++i)
  {
    if (stepsRe[i] == preStep)
      continue;
    // 正向旋转过去
    // a,b 要转的位置
    a = steps[i][0] + preA;
    b = steps[i][1] + preB;
    if (a < 0 || a > 2 || b < 0 || b > 2)
      continue;
    for (j = 0; j < 3; ++j)
      stateArr[preA][preB][j] = stateArr[a][b][stepChange[i][j]];
    emptyPos[0] = a;
    emptyPos[1] = b;
    stateArr[a][b][0] = 0;

    dfs(step + 1, i);

    // 反向旋转回来
    for (j = 0; j < 3; ++j)
      stateArr[a][b][j] = stateArr[preA][preB][stepChange[stepsRe[i]][j]];
    emptyPos[0] = preA;
    emptyPos[1] = preB;
    stateArr[preA][preB][0] = 0;
  }
}

int main()
{
  int i, j, k, jnum;
  char c;
  while (scanf("%d %d", &emptyPos[1], &emptyPos[0]) == 2)
  {
    minStep = 1000;
    if (emptyPos[0] == 0 || emptyPos[1] == 0)
      return 0;
    emptyPos[0]--;
    emptyPos[1]--;
    // 读入换行符
    getchar();
    for (i = 0; i < 3; ++i)
    {
      for (j = 0; j < 3; ++j)
      {
        scanf("%c", &c);
        // 白色1 蓝色2 红色3 空0
        switch (c)
        {
        case 'W':
          k = 1;
          break;
        case 'B':
          k = 2;
          break;
        case 'R':
          k = 3;
          break;
        case 'E':
          k = 0;
          break;
        }
        goal[i][j] = k;
        // 读入一个分隔符
        getchar();
      }
    }
    // 初始化当前状态
    for (i = 0; i < 3; ++i)
    {
      for (j = 0; j < 3; ++j)
      {
        stateArr[i][j][0] = 1;
        stateArr[i][j][1] = 3;
        stateArr[i][j][2] = 2;
      }
    }
    stateArr[emptyPos[0]][emptyPos[1]][0] = 0;
    dfs(0, -1);

    if (minStep > 30)
      printf("-1\n");
    else
      printf("%d\n", minStep);
  }
  return 0;
}
相关推荐
CoovallyAIHub1 小时前
CVPR 2026 | MixerCSeg:仅2.05 GFLOPs刷新四大裂缝分割基准!解耦Mamba隐式注意力,CNN+Transformer+Mamba三
深度学习·算法·计算机视觉
CoovallyAIHub2 小时前
YOLO26-Pose 深度解读:端到端架构重新设计,姿态估计凭什么跨代领先?
深度学习·算法·计算机视觉
CoovallyAIHub2 小时前
化工厂气体泄漏怎么用AI检测?30张图3D重建气体泄漏场景——美国国家实验室NeRF新研究
深度学习·算法·计算机视觉
颜酱14 小时前
图的数据结构:从「多叉树」到存储与遍历
javascript·后端·算法
zone773919 小时前
006:RAG 入门-面试官问你,RAG 为什么要切块?
后端·算法·面试
CoovallyAIHub1 天前
OpenClaw 近 2000 个 Skills,为什么没有一个好用的视觉检测工具?
深度学习·算法·计算机视觉
CoovallyAIHub1 天前
CVPR 2026 | 用一句话告诉 AI 分割什么——MedCLIPSeg 让医学图像分割不再需要海量标注
深度学习·算法·计算机视觉
CoovallyAIHub1 天前
Claude Code 突然变成了 66 个专家?这个 5.8k Star 的开源项目,让我重新理解了什么叫"会用 AI"
深度学习·算法·计算机视觉
兆子龙1 天前
前端哨兵模式(Sentinel Pattern):优雅实现无限滚动加载
前端·javascript·算法
CoovallyAIHub1 天前
9个视觉语言模型工厂实测:Qwen 87.9%碾压全场,你的显卡能跑哪个?
算法