笔记:记录状态并判重的方法

embedded/2024/12/21 20:37:56/

题目(八数码问题)

编号为1-8的8个正方形滑块被摆成3行3列(有一个格子留空),如下图所示

815
736
42

每次可以把与空格相邻的滑块(有公共边才算相邻)一道空格中,而它原来的位置就成为了新的空格。给定初始局面和目标局面(用0表示空格),你的任务是计算出最少的移动步数。如果无法到达目标局面,则输出-1

解法思路

简单来说就是无权图的最短路径问题(和我昨天看到的魔方问题差不多),可以用bfs来做

如果想看看有权图的最短路径问题,可以看看下面这题:

OpenJudge - 19G:海拔

我做这题的思路:

好了言归正传

这题难点在于对状态的记录的问题:如果声明一个9维数组vis,总共有9^9=387420489个项,太多了,内存直呼根本塞不下。如果把9个元素合并成一个数字,最大的数字是876543210,甚至更大

而实际的结点数量并没有这么多,0~8的全排列只有9!= 362990个,如果按照上面的方法,有大量的内存会被浪费

方法一

直接使用STL的集合set。把状态转化为9位十进制整数,就可以用set<int>判重了

set<int> vis;
void init_lookup_table{vis.clear();}
int try_to_insert(int s){int v = 0;//将s中的状态转化为数字并放入v中(伪代码)if(vis.count(v)) return 0;vis.insert(v);return 1;
}

很简单对吧,但是效率低,建议在时间紧迫或对效率要求不太高的情况下使用

方法二

把排列“变成”整数,然后只开一个一维数组。也就是说,设计一套排列的编码和解码函数,把0~8的全排列和0~362879的整数一一对应起来

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; //把st[s]映射到整数code(st为二维数组,记录状态,第二维记录各个数字)for(int i = 0; i < 9; i++){int cnt = 0;for(int j = i + 1; j < 0; j++) if(st[s][j] < st[s][i]) cnt++;code += fact[8 - i] * cnt;}if(vis[code]) return 0;return vis[code] = 1;
}

屌吧,屌爆了

原理巧妙(我根本想不到),时间效率也非常高,但编码解码法的适用范围并不大:如果总结点数非常大,编码也会非常大,数组还是开不下

方法三

想必诸位都猜到了

使用哈希技术。简单地说,就是要把结点“变成”整数,但是不必一一对应。换句话说,只需设计一个所谓的哈希函数h(x),然后将任意结点x映射到某个给定范围[0, M - 1]的整数即可,其中M是程序员根据可用内存大小自选的。在理想情况下,只开一个大小为M的数组就能完成判重,但此时往往会有不同结点的哈希值相同,因此需要把哈希值相同的状态组织成链表

typedef int State[9];
const int hashsize = 1000003;
const int maxstate = 1000000;State st[maxstate];//状态数组
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];//把9个数字组成9位数return v % 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;
}


http://www.ppmy.cn/embedded/53884.html

相关文章

B3850 [GESP202306 四级] 幸运数

特殊原因&#xff0c;学校请2.5天假 [GESP202306 四级] 幸运数 题目描述 小明发明了一种 "幸运数"。一个正整数&#xff0c;其偶数位不变&#xff08;个位为第 1 位&#xff0c;十位为第 2 位&#xff0c;以此类推&#xff09;&#xff0c;奇数位做如下变换&#x…

重生奇迹MU 非常适合新人的职业推荐

如果你是一位新手玩家&#xff0c;刚刚踏入重生奇迹MU 的世界&#xff0c;那么你一定会面临职业选择的难题。毕竟&#xff0c;每个职业都有独特的技能和特点&#xff0c;很难决定哪一个最适合自己。为了帮助你快速适应这个游戏&#xff0c;我们为你推荐几个非常适合新手的职业&…

Node.js全栈指南:看官方文档的艺术

上回我们说到啊&#xff0c;创建了一个极简的 Web 服务&#xff0c;监听了端口&#xff0c;设置了正确的编码&#xff0c;成功地在浏览器看到了返回的内容 “你好&#xff0c;世界&#xff01;”。 那么本章节呢&#xff0c;我们通过一个简单的例子来分析&#xff0c;如何有效…

查看Angular CLI的可使用版本并同时安装指定版本。

要查看Angular CLI&#xff08;angular/cli&#xff09;可以使用的版本&#xff0c;你可以采取以下几种方法&#xff1a; 1. 使用 npm 查看版本 你可以使用以下命令来查看 npm 上可用的 angular/cli 版本&#xff1a; npm show angular/cli versions --json 这个命令会返回…

npm报错:request to https://registry.npm.taobao.org failed处理办法

npm报错&#xff1a;request to https://registry.npm.taobao.org failed处理办法 npm报错&#xff1a;request to https://registry.npm.taobao.org failed, reason certificate has expired 看提示是淘宝镜像过期了。找了一下资料&#xff0c;好像是npm 淘宝镜像已经从 regi…

坎德拉candela3d光伏电站三维设计软件【无标题】

Candela3D 是一款基于 SketchUp&#xff08;草图大师&#xff09;开发的新一代光伏电站三维设计软件。它适用于复杂地形、平坦地形光伏电站的建设项目&#xff0c;同时适用于可研、初设、施工图、项目运营等阶段。这款软件具有多项功能&#xff0c;例如&#xff1a; • 能够突…

osi七层参考模型和tcp/ip模型的区别与相似之处

osi七层参考模型&#xff1a; 2.tcp/ip四层参考模型&#xff1a; osi七层参考模型与tcp/ip四层参考模型的相似与区别&#xff1a; 相同点&#xff1a; 2者都是模型化层次化 下层对上层提供服务支持 每层协议彼此相互独立 不同点&#xff1a;OSI先有模型才有协议 TCP/IP先有…

flex 与 overflow 冲突

问题场景&#xff1a; 父盒子高度会变化&#xff0c;可能会比子盒子大&#xff0c;也可能会比子盒子小。 比子盒子大的时候&#xff0c;希望子盒子垂直居中&#xff1b;比子盒子小的时候&#xff0c;能够正常滚动&#xff1b; <body><div class"outer">…