<p>/*
因为注释很详细,就直接上代码了,需要注意的是,用了白书的三种方法来进行判重,其中最快捷的方法还是stl的set,还有哈希技术涉及到了多个链表的处理,还有一种就是编码解码技术,这个需要找到一个非常好的函数才能达到一一对应。而哈希表不需要一一对应(因为有链表)。</p><div>*/</div>//
//  main.cpp
//  EightBits
//
//  Created by LinYuchen on 2/13/15.
//  Copyright (c) 2015 LinYuchen. All rights reserved.
//八数码问题 暂时不用启发式(A*)只是想锻炼结点查找表(判重)的部分
//http://codevs.cn/problem/1225/#include <iostream>
#include <set>
#include <string>
#define MAXSTATE 10000
using namespace std;
typedef int State[9];//把棋盘的九个位置存起来当做一个状态 State
State goal;//用来存储最后想达到的状态
State st[MAXSTATE];//用来存储从启示到达终点的所有状态过程 实际上是个队列 因为是 bfs
int dist[MAXSTATE];//用来存储每一个走到st里的每一个state都已经走了多少步 (why?)
int d = 0;
//进行坐标变换 分别是上下左右
int dx[]={-1,1,0,0},dy[]={0,0,-1,1};
int bfs();//宽度优先搜索来找到最短路径(图的最短路径)
void init_lookup_table();//初始化查找表
bool try_to_insert(int rear);//尝试插入,进行判重如果已经走过就返回false不许插入队列
int getId(int x,int y){return (x-1)*3+y-1;}//第x行 第y列 x=1,2,3 y=1,2,3int bfs(){init_lookup_table();int front=1,rear=2;//队列的头指针是1 尾指针是2(牢记:尾指针指向的是现有的最后一个元素的下一个位置)while (front<rear) {//front<rear 可以用来判断队列是否非空State& s = st[front];//此时的s表示的是此时的队首状态,也是即将进行发生变化的/*判断待处理的s是否正好就是goal 也就是达到了目的否?//如果已经找到了直接返回front 在结尾处我们可以通过front在st中找到goal*/if(memcmp(goal, s, sizeof(State))==0)return front;//如果可以进行到这里 说明我们要进行移动空白格(0)了//想移动空白格 首先要找到它int i=0;for (;i<9;i++)if(!s[i]) break;int zero_x=i/3+1 , zero_y=i%3+1;//转成坐标 和白书不同//开始进行四个方向的移动 需要进行出界判断for (int t=3; t>=0; t--){int newx = zero_x+dx[t],newy=zero_y+dy[t];if(newx<=3 and newx>=1 and newy>=1 and newy<=3){int new_zero = getId(newx,newy);//如果移动是合法的 就开始进行向队尾加入元素State& r = st[rear];//r是从s上移动而来的 所以只需要进行微调memcpy(&r, &s, sizeof(State));//swap(r[new_zero],r[i]);//i是s中0的位置 new_zero是0移动之后的位置r[new_zero]=s[i];r[i]=s[new_zero];dist[rear] = dist[front]+1;//front可以取到没有移动之前的距离//尝试把移动之后的状态进行插入队列继续走,如果发现已经重复则不进行rear++//rear++表示已经插入了队列,否则即使占领了st[rear]也会被下一次循环覆盖if(try_to_insert(rear)) rear++;}}front++;//不管怎样都是处理完了一个~所以要出队}//如果没有找到任何的路径那么就返回0return 0;
}//对应set的方式 init函数是//利用stl的set进行判重 集合的互异性 set的元素类型必须重载 < 运算 所以有限考虑int
set<int> vis;
void init_lookup_table(){vis.clear();}//对vis集合进行清空
bool try_to_insert(int rear){//首先要把state转换成一个一一对应的int 才能插入集合来判断int id =0;for (int i=0; i<9; i++) id += st[rear][i] + id*10;//第一种检查方法是用find函数 和 end函数来进行比较 这里原理不是很清楚//if(vis.find(id)==vis.end()) return false;//第二种用count函数来进行判断 依然不懂得原理if(vis.count(id)!=0) return false;vis.insert(id);return true;
}//对应编码解码的方法判重bool vis[362880];int fact[9];//vis的长度是由9!确定的,fact[i]存的是i的阶乘
void init_lookup_table(){memset(vis, false, sizeof(bool));//初始化fact数组 保存每个数的阶乘 为了以后使用方便fact[0]=1;for(int i=1;i<=8;i++) fact[i]=i*fact[i-1];
}
bool try_to_insert(int rear){//进行编码 编码之后看vis是否int code = 0;for(int i =0;i<9;i++){int cnt =0;//cnt是为了记录st[rear][i]后面有几个比他小的数for (int j=i+1; j<9; j++) if(st[rear][j]<st[rear][i]) cnt++;code += fact[8-i]*cnt;//编码方式比较奇怪}//code是个 sigma(i=0-8) (8-i)!*第i个数后面比它小的数的个数。if (vis[code])     return false;vis[code]=true;    return true;
}
//最优方式 hash链表技术
const int MAXHASHSTATE = 1000003;//这个常数是hash值的范围(最大值)
int head[MAXHASHSTATE],nextState[MAXSTATE];
//head的下表是hash值,我们可以通过下标(也就是hash值)去访问这个hash值所对应的state
//也就是说head数组里的每个值其实是st数组的下标
//next是链表 一条链是同一哈希值 一个state接一个state 所以next数组的下标和值都是st的下标int getHash(int t){//返回哈希值int hash_value = 0;for (int i=0; i<9; i++)hash_value += hash_value*10+st[t][i];return hash_value%MAXHASHSTATE;
}
void init_lookup_table(){ memset(head, 0, sizeof(int));memset(nextState, 0, sizeof(int));}
bool try_to_insert(int rear){int hv = getHash(rear);int u = head[hv];//找到此哈希值对应的state 没有就是0 如果有就是这条哈希链的首个while(u){//循环地去看这条链子if(memcmp(st[u], st[rear], sizeof(State))==0) return false;//重复//如果不重复那么就在这个链子上继续寻找u = nextState[u];//如果没有了u就会变成0}//循环完整条链子 没有发现重复 那么就要在这条链子的头部插入当前元素nextState[rear]=head[hv];//注意是插在头部,所以rear的下一个是当前的头部head[hv]=rear;return true;
}int main(int argc, const char * argv[]) {//初始化目标状态
//    for (int i=0; i<8; i++)
//        goal[i]=i+1;
//    goal[8]=0;
//char goal_str[] = "123804765";for (int i=0; i<9; i++) {goal[i]=goal_str[i]-'1'+1;}//进行输入State& start=st[1];//引用地址来进行改名字 主要是为了简化代码dist[1]=0;        //用1是为了配合bfs 0表示没有char start_state[9];cin>>start_state;for (int i=0; i<9; i++)start[i]=start_state[i]-'1'+1;d = dist[bfs()];cout<<d<<endl;return 0;
}

转载于:https://www.cnblogs.com/yuchenlin/p/4379253.html

【算法学习笔记】18.暴力求解法06 隐式图搜索2 八数码问题 未启发相关推荐

  1. 虎书学习笔记4:图形学基础数学(隐式二维直线、隐式二次曲线、二维参数曲线、二维参数直线、二维参数圆)

    关于图形学的基础数学知识 基础数学 隐式二维直线 我们最熟悉的直线:斜截式 他的隐式方程为: 我们再函数y-mx-b=0两边同乘一个系数,将得到一摸一样的直线. 因为两个点觉得一条直线,所以必然满足: ...

  2. 初探swift语言的学习笔记二(可选类型?和隐式可选类型!)

    作者:fengsh998 原文地址:http://blog.csdn.net/fengsh998/article/details/28904115 转载请注明出处 如果觉得文章对你有所帮助,请通过留言 ...

  3. (紫书,感谢作者)第7章暴力求解法

    今天,我们谈一谈紫书上面的内容--暴力求解法 对于一道问题来说,我们是可以借助计算机运算快的特点,将所有可能的情况全部(不一定是全部)列出来,然后去寻找我们想要的答案,这就是暴力求解了,但暴力求解绝对 ...

  4. Python最优化算法学习笔记(Gurobi)

    微信公众号:数学建模与人工智能 github地址:https://github.com/QInzhengk/Math-Model-and-Machine-Learning Python最优化算法学习笔 ...

  5. 网络流算法学习笔记——最大流问题基本概念和Ford-Fulkerson方法(标号法C++实现)

    屈婉玲<算法设计与分析>第2版第7章网络流算法学习笔记. 基本概念 最大流问题,相当于有从s到t的供水系统,每段路径都有限定流量,除了s.t两地外,每个中间点都不能滞留,从s流入多少,就从 ...

  6. 数据结构与算法 学习笔记(5):字符串

    数据结构与算法 学习笔记(5)- 字符串 本次笔记记录了LeetCode中关于字符串的一些问题,并给出了相应的思路说明和代码.题目编号与LeetCode对应,方便查找. 题目1:LeetCode 13 ...

  7. Manacher算法学习笔记 | LeetCode#5

    Manacher算法学习笔记 DECLARATION 引用来源:https://www.cnblogs.com/grandyang/p/4475985.html CONTENT 用途:寻找一个字符串的 ...

  8. l2-004 这是二叉搜索树吗?_算法学习笔记(45): 二叉搜索树

    二叉搜索树(Binary Search Tree, BST)是一种常用的数据结构,在理想情况下,它可以以 的复杂度完成一系列修改和查询,包括: 插入一个数 删除一个数 查询某数的排名(排名定义为比该数 ...

  9. 两个字符串的最长公共子序列长度_算法学习笔记(58): 最长公共子序列

    (为什么都更了这么多篇笔记了,这时候才讲这么基础的内容呢?因为我本来以为LCS这种简单的DP不用讲的,结果CF不久前考了LCS的变式,然后我发现由于自己对LCS一点都不熟,居然写不出来 ,于是决定还是 ...

最新文章

  1. 57-高级路由:分发列表:多协议分发列表实验:DV、LS
  2. vectornator安卓_Vectornator Pro
  3. 一看就懂的动态规划入门教程
  4. MATLAB库函数resample(重新采样序列)的C语言实现
  5. 简易封装手机浏览器touch事件
  6. 依图做语音了!识别精度创中文语音识别新高点
  7. 混亂的思維 ~ 很高興能邂逅到常年不見的竹子
  8. GNSS说第(三)讲---最新的GNSS观测数据及精密星历等产品的下载方式及地址
  9. csv转vcf格式网页工具-快速导入手机通讯录
  10. fibonacci数列java大赛_斐波那契数列 java 解法
  11. Axure原型设计灯箱效果
  12. 苹果系统无法购买服务器,itunes目前无法处理您的购买怎么解决
  13. String s与String s = ““的区别
  14. 敬天爱人 大道至简——初读《经营十二条》
  15. DEV-C++对c文件提示无法编译的问题
  16. 无偏性、有效性、一致性
  17. 图像审核产品“侦图” —— Milvus 在翼支付风控场景中的应用
  18. 互联网行业应届生年薪35W,倒挂老员工,这是逼老人离职吗?
  19. go 源码工具解析-英文单复数变化 Inflection
  20. vue3 require.context 实现基础组件的自动化全局注册 模块自动化加载(霸霸看了都说好)

热门文章

  1. 全球及中国发酵酸行业发展动态及投资前景预测报告(新版)2022-2027
  2. php cms 路径访问问题,phpcms教程:网站安装完后访问总是跳转到安装目录路径
  3. RC串联对RC并联的等效阻抗转换及仿真
  4. ABB机器人编程基础_手动示教+记录+修改点位数据的具体方法和步骤示例
  5. 2022北航敏捷软件工程 第四次博客作业
  6. ELK—x-pack插件
  7. css设计软件dw,教你在Dreamweaver中使用CSS设计布局
  8. 魔百和M401A刷入Armbian系统EMMC
  9. 测试游戏的软件电脑运行,什么是软件性能测试_电脑测试性能软件_测试电脑游戏性能软件...
  10. 小程序毕业设计 基于微信棋牌室小程序毕业设计开题报告功能参考