由八数码问题引入。对BFS有更深考虑
12号到今天共研究八数码问题poj1077,首先用的是普通BFS,遇到很多问题,开始用一个二级指针作为结构成员,知道了二级指针与二维数值名的不同!http://write.blog.csdn.net/postedit!讲得不错。发现自己代码能力渣死!进入正题,用BFS过不了,先学习了八数码问题有解条件,并扩展到N数码有解问题。做到奇数偶数剪枝,过不了,太慢,于是学习了HASH判重,学习了康托展开(排列与数字的一一对应关系),效率大大增加!但是别人这样过了都,我是过不了啊!于是去学双广!没怎么看明白,,,很想放弃了!于是去学习了A*算法!(启发式搜索),46ms,BFS是最普通的A*,那么,我用优先队列优化,设置启发函数,把优先级高的先出队!本质已经破坏了BFS的分层搜索,倒是有点DFS了,我名之为bdfs!,有方向性!这样找一组解很容易!不用遍历所有!
于是去切了骑士问题,先是8格的的,再是n格的,接下!
#include<iostream> //优先(小的优先)队列BFS+hash判重+奇数偶数剪枝
#include<queue>
#include<string>
#include<cstdio>
#include<set>
#include<cstring>
using namespace std;
string a;
int f[4][2]={0,1,0,-1,1,0,-1,0};//方向
bool state[362881];
int fac[10]={1,1,2,6,24,120,720,5040,40320,362880};
struct xy
{
string aa; //当前状态
int x; //空格的坐标
int y;
int abs_to_end; //和目标数相同的方块数目!
string s; // 字符串,保存当前移动情况
bool operator < (const xy & now) const //自定义离目标小的优先!
{
return now.abs_to_end>abs_to_end;
}
};
int get_abs(string aa) //只要第一次获得,其他改变修改
{
int res=0;
for(int i=1;i<=9;i++)
{
if(aa[i]!='9'&&aa[i]==('0'+i))res++;
}
return res;
} bool has_solution() //无解条件,奇偶剪枝!
{
int t[9];int count=0;
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
t[count++]=a[i*3+j]-'0';
count=0;
for(int i=0;i<9;i++)
for(int j=i+1;j<9;j++)
if(t[j]!=9&&t[i]!=9&&t[j]<t[i])count++;
if(count%2==0)return 1;
return 0;
}
string bfs(int ox,int oy) //
{
priority_queue<xy>q;
xy dian; dian.x=ox;dian.y=oy; //赋初值
dian.s=""; //首地址的赋值,二维数组必先从一维建立。用的还是同一个! for(int i=0;i<3;i++)
{
for(int j=0;j<3;j++)
{
dian.aa+=a[i*3+j];
}
}
dian.abs_to_end=get_abs(dian.aa);
q.push(dian);
if(dian.aa=="123456789")return dian.s;
while(!q.empty())
{
xy temp=q.top();
q.pop(); //取队首拓展
for(int i=0;i<4;i++)
{ // xy next=temp;这样只是完全赋值,指针指的是同一块地址!
xy next(temp);
int space=next.x*3+next.y;
next.x=next.x+f[i][0]; //四个方向拓展。
next.y=next.y+f[i][1];
if(next.x>=0&&next.x<3&&next.y>=0&&next.y<3)
{
if(i==0)
{
if(next.s.size()>0&&'l'==next.s[next.s.size()-1])continue;
next.s+="r";
if(next.aa[space+1]=='1'+space+1)next.abs_to_end--;
if(next.aa[space+1]=='1'+space)next.abs_to_end++;
next.aa[space]=next.aa[space+1];
next.aa[space+1]='9';
}
else if(i==1)
{
if(next.s.size()>0&&'r'==next.s[next.s.size()-1])continue;
next.s+="l";
if(next.aa[space-1]=='1'+space-1)next.abs_to_end--;
if(next.aa[space-1]=='1'+space)next.abs_to_end++;
next.aa[space]=next.aa[space-1];
next.aa[space-1]='9';
}
else if(i==2)
{
if(next.s.size()>0&&'u'==next.s[next.s.size()-1])continue;
next.s+="d";
if(next.aa[space+3]=='1'+space+3)next.abs_to_end--;
if(next.aa[space+3]=='1'+space)next.abs_to_end++;
next.aa[space]=next.aa[space+3];
next.aa[space+3]='9';
}
else if(i==3)
{
if(next.s.size()>0&&'d'==next.s[next.s.size()-1])continue;
next.s+="u";
if(next.aa[space-3]=='1'+space-3)next.abs_to_end--;
if(next.aa[space-3]=='1'+space)next.abs_to_end++;
next.aa[space]=next.aa[space-3];
next.aa[space-3]='9';
}
if(next.aa=="123456789")return next.s;
string ts=next.aa; //int hash(string ts)
int res=0;
for(int i=0;i<9;i++)
{
int count=0;
for(int j=i+1;j<9;j++)
if(ts[j]<ts[i])count++;
res+=count*fac[9-i-1];
}
if(state[res])continue;
state[res]=true;
q.push(next);
}
}
}
}
int main()
{
string ta;
while(getline(cin,ta))
{
int ox,oy;
a.clear();
for(int i=0;i<ta.size();i++)
{
if(ta[i]=='x') a+='9';
else if(ta[i]!=' ')a+=ta[i];
}
for(int i=0;i<a.size();i++)
{
if(a[i]=='9'){ox=i/3;oy=i%3;}
}
memset(state,0,sizeof(state));
if(!has_solution())cout<<"unsolvable"<<endl;
else
{
cout<<bfs(ox,oy)<<endl;
}
}
return 0;
}
由八数码问题引入。对BFS有更深考虑的更多相关文章
- 习题:八数码难题(双向BFS)
八数码难题(wikioi1225) [题目描述] 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中.要求解的问题是:给出 ...
- HDU-1043 Eight八数码 搜索问题(bfs+hash 打表 IDA* 等)
题目链接 https://vjudge.net/problem/HDU-1043 经典的八数码问题,学过算法的老哥都会拿它练搜索 题意: 给出每行一组的数据,每组数据代表3*3的八数码表,要求程序复原 ...
- hdu1043Eight (经典的八数码)(康托展开+BFS)
建议先学会用康托展开:http://blog.csdn.net/u010372095/article/details/9904497 Problem Description The 15-puzzle ...
- Eight(South Central USA 1998)(八数码) 分类: bfs 2015-07-05 22:34 1人阅读 评论(0) 收藏
The 15-puzzle has been around for over 100 years; even if you don't know it by that name, you've see ...
- 【洛谷P1379】八数码难题 状压bfs
对于这道题来说,每个时刻的状态是整个棋盘所有棋子的位置,即:任何一个棋子位置发生了移动,都会使得状态转移. 因此,需要采取将整个状态作为广搜的搜索对象,进行状态压缩.采用哈希得到每个状态的对应的数值, ...
- 洛谷 P1379 八数码难题(map && 双向bfs)
题目传送门 解题思路: 一道bfs,本题最难的一点就是如何储存已经被访问过的状态,如果直接开一个bool数组,空间肯定会炸,所以我们要用另一个数据结构存,STL大法好,用map来存,直接AC. AC代 ...
- BFS(八数码) POJ 1077 || HDOJ 1043 Eight
题目传送门1 2 题意:从无序到有序移动的方案,即最后成1 2 3 4 5 6 7 8 0 分析:八数码经典问题.POJ是一次,HDOJ是多次.因为康托展开还不会,也写不了什么,HDOJ需要从最后的状 ...
- UVALive 6665 Dragonâs Cruller --BFS,类八数码问题
题意大概就是八数码问题,只不过把空格的移动方式改变了:空格能够向前或向后移动一格或三格(循环的). 分析:其实跟八数码问题差不多,用康托展开记录状态,bfs即可. 代码: #include <i ...
- [cdoj1380] Xiper的奇妙历险(3) (八数码问题 bfs + 预处理)
快要NOIP 2016 了,现在已经停课集训了.计划用10天来复习以前学习过的所有内容.首先就是搜索. 八数码是一道很经典的搜索题,普通的bfs就可求出.为了优化效率,我曾经用过康托展开来优化空间,甚 ...
随机推荐
- WEB前端学习有用的书籍
WEB前端研发工程师,在国内算是一个朝阳职业,这个领域没有学校的正规教育,大多数人都是靠自己自学成才.本文主要介绍自己从事web开发以来(从大二至今)看过的书籍和自己的成长过程,目的是给想了解Java ...
- Runtime理解
动态语言 OC是一门不折不扣的动态语言,所以它的很多机制都是动态运行时决定的.这点和C语言不一样,C语言是静态绑定,也就是编译后所有的一切都已经决定了.这一点和C语言的函数指针有些类似,很多时候函数指 ...
- mysql 函数tree状
// 子节点的查询 CREATE DEFINER = `root`@`%` FUNCTION `getDeptChildList`(rootId BIGINT) RETURNS longtext DE ...
- Linux之基础命令——文件搜索
grep(匹配符合条件的字符串) 无参:显示匹配行 -c:显示匹配行数 -e 字符串:匹配特殊字符串,如-开头 -i:忽略大小写 -v:输出不匹配行 -w:匹配指定字符串 可以和别的命令通过" ...
- .NET多线程总结
1.不需要传递参数,也不需要返回参数 我们知道启动一个线程最直观的办法是使用Thread类,具体步骤如下: public void test() { ThreadStart threadStart = ...
- 获取声音设备名称及PNPDeviceID
实现效果: 知识运用: WMI管理类中的 ManagementObjectSearcher类 //基于指定的查询检索管理对象的集合 用于检索管理信息的较为常用的入口点之一 public Managem ...
- 通俗理解 模糊自适应PID
模糊自适应PID算法就是在经典的PID的基础上添加模糊控制规则库,建立这个库的目的就是算法能够自己来进行改变P.I.D的值. 就拿温度的上升过程控制来说,刚开始的时候,希望温度能够快速的升到终点温度, ...
- Hibernate5.x版本HQL限定查询 Legacy-style query parameters (`?`) are no longer supported
在此版本的限定查询和4.0版本的限定查询: 如果查询语句是: String hql = "select u from User u where u.gender = ?"; 会出现 ...
- 【转】NIO的定义和原理是什么?
NIO和IO到底有什么区别?有什么关系? 首先说一下核心区别: NIO是以块的方式处理数据,但是IO是以最基础的字节流的形式去写入和读出的.所以在效率上的话,肯定是NIO效率比IO效率会高出很多. N ...
- java内存模型(线程独占部分)
线程独占部分 1.你了解Java的内存模型吗? 内存简介 有内核空间.用户空间(java是运行在用户空间上) 32位系统--->最大的访问内存大小是4G 62位系统--->最大的访问内存大 ...