当前位置: 首页 > news >正文

八数码(bfs)

关于八数码问题的三种实现方式

#include<cstdio>
#include<cstring>
using namespace std;typedef int State[9];
const int maxstate = 1000000;
State st[maxstate], goal;
int dist[maxstate];const int dx[] = {1,-1,0,0};
const int dy[] = {0,0,-1,1};bool inside(int x, int y) {return 0 <= x && x < 3 && 0 <= y && y < 3;
}const int hashsize = 1000003;
int head[hashsize], next[maxstate];
void init_lookup_table() { memset(head,0,sizeof(head)); }
int hash(State & s) {int v = 0;for(int i = 0; i < 9; ++i) v = v*10 + s[i];return v % hashsize;
}
bool 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 bfs() {init_lookup_table();int front = 1, rear = 2;while(front < rear) {State & s = st[front];if(memcmp(goal,s,sizeof(s)) == 0) return front;int z;for(z = 0; z < 9; ++z) if(!s[z]) break;int x = z/3, y = z%3;for(int d = 0; d < 4; ++d) {int nx = x + dx[d];int ny = y + dy[d];int nz = nx*3 + ny;if(inside(nx,ny)) {State & t = st[rear];memcpy(&t,&s,sizeof(s));t[nz] = s[z];t[z] = s[nz];dist[rear] = dist[front] + 1;if(try_to_insert(rear)) ++rear; } }++front;}return 0;
}int main() {for(int i = 0; i < 9; ++i) scanf("%d",&st[1][i]);for(int i = 0; i < 9; ++i) scanf("%d",&goal[i]);int ans = bfs();if(ans > 0) printf("%d\n",dist[ans]);else printf("-1\n");return 0;
}

这段代码虽简短,但却有很多细节和小技巧。下面一一说明

1: 程序将八数码的状态单元int[9]直接用typedef替换为State,并定义状态队列st,最终目标goal,便于阅读和编码。

2: 在初始读入数据时,直接把初始状态读入队列的第一个'状态'中,将目标状态读入goal

3: bfs中采用内存控制函数memcpy赋值和memcmp判断,高效简洁。

4: 八数码属于隐式图搜索问题,因此要在普通bfs上增加一个"结点查找表"来判重。本程序采用自己设计的hash表来判重。下面还有两种实现方式,分别是"完美哈希"和STL中的set。

//完美hash
int vis[362880], fact[9];
void init_lookup_table() {fact[0] = 1;for(int i = 1; i < 9; ++i) fact[i] = fact[i-1] * i;
}
int try_to_insert(int s) {int code = 0;for(int i = 0; i < 9; ++i) {int cnt = 0;for(int j = i+1; j < 9; ++j) if(st[s][j] < st[s][i]) ++cnt;code += fact[8-i] * cnt;}if(vis[code]) return 0;return vis[code] = 1;
}
//STL
set<int> vis;
void init_lookup_table() { vis.clear(); }
int try_to_insert(int s) {int v = 0;for(int i = 0; i < 9; ++i) v = v*10 + st[s][i];if(vis.count(v)) return 0;vis.insert(v);return 1;
}
http://www.aitangshan.cn/news/200.html

相关文章:

  • 我真的绷不住了
  • 欧拉回路
  • 8月11号
  • Orleans框架
  • ABC418——XNOR - love
  • 代码随想录算法训练营第五天(哈希表篇)|Leetcode242有效的字母异位词,Leetcode349两个数组的交集,Leetcode202快乐数,Leetcode1两数之和
  • 7种形态图
  • 百度智能云给“数字人”发工牌 - 详解
  • 1
  • 2025.8.11.模拟赛题目记录
  • Mysql 授予root在任意主机访问数据库的权限
  • Awesome Claude Code 资源大全
  • JAVA方法
  • echarts初始化占不满div, F12后又占满了
  • docker Ubuntu Docker 安装
  • arm LDR指令
  • QNAP QTS SSL Certificate 证书更新修复
  • Python入门学习(九)Python的高级语法与用法(二)闭包
  • 工程师团队如何打造4K流媒体设备的创新技术
  • 【题解】P4063 [JXOI2017] 数列
  • mount: /mnt/hgfs/vm_share: unknown filesystem type vmhgfs - hbg
  • 8月11日总结
  • OpenCV-鱼眼相机图像处理
  • 新高一暑假二期集训 Week 1
  • ZR 25 summer D6T1 题解 | 思维、数学(计算几何)
  • 线程安全的集合类 ConcurrentQueue、ConcurrentStack、BlockingCollection、ConcurrentBag、ConcurrentDictionary
  • 【自学嵌入式:stm32单片机】对射式红外传感器记次
  • Rime-weasel 中州韻輸入法-小狼毫 输入法候选框不显示拼音的解决办法
  • 从美世《中国员工敬业度员工体验白皮书》看AI如何改善员工体验
  • 线程安全的集合类 ConcurrentQueue、BlockingCollection、ConcurrentBag