特别声明:紫书上抄来的代码,详见P198

题目描述

在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字。棋盘中留有一个空格,空格用0来表示。空格周围的棋子可以移到空格中。要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变。

输入输出格式

输入格式:

输入初试状态,一行九个数字,空格用0表示

输出格式:

只有一行,该行只有一个数字,表示从初始状态到目标状态需要的最少移动次数(测试数据中无特殊无法到达目标状态数据)

输入输出样例

输入样例#1:

283104765
输出样例#1:

4

判重一 //set

代码

 #include<iostream>
#include<cstring>
#include<cstdio>
#include<set>//测试
#include<algorithm>
using namespace std;
typedef int state[]; state st[],goal={,,,,,,,,};
int dis[],dx[]={-,,,},dy[]={,,-,}; set<int> vis;
void init_lookup_table(){vis.clear();}
int try_to_insert(int s){
int v=;
for(int i=;i<;i++)v=v*+st[s][i];
if(vis.count(v)) return ;
vis.insert(v);
return ;
} int bfs(){
init_lookup_table();
int front=,rear=;
while(front<rear){
state& s=st[front];
if(memcmp(goal,s,sizeof(s))==)return front; int z;
for(z=;z<;z++) if(!s[z]) break;
int x=z/,y=z%;
for(int d=;d<;d++){
int newx=x+dx[d];
int newy=y+dy[d];
int newz=newx*+newy;
if(newx>=&&newx<&&newy>=&&newy<){
state& t=st[rear];
memcpy(&t,&s,sizeof(s));//Copy
t[newz]=s[z];
t[z]=s[newz];
dis[rear]=dis[front]+;
if(try_to_insert(rear)) rear++;
}
}
front++;
}
return ;
} int main(){
// freopen("01.in","r",stdin);
string s;cin>>s;
for(int i=;i<=;i++)st[][i]=s[i]-''; int ans=bfs();
if(ans>) printf("%d\n",dis[ans]);
else printf("-1\n");
return ;
}

紫书上说stl很慢,但是......

膜拜洛谷测评机

不过这是一个好方法吧.比如状态很多但很分散就可以类比set

判重二 //hash

代码

#include<iostream>
#include<cstring>
#include<cstdio>
#include<set>//测试
#include<algorithm>
using namespace std;
typedef int state[]; state st[],goal={,,,,,,,,};
int dis[],dx[]={-,,,},dy[]={,,-,}; const int hashsize=;
int head[hashsize],next[hashsize];
void init_lookup_table(){memset(head,,sizeof(head));}
int hash(state& s){
int v=;
for(int i=;i<;i++) v=v*+s[i];
return v%;
}
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]))== )return ;
u=next[u];
}
next[s]=head[h];
head[h]=s;
return ;
} int bfs(){
init_lookup_table();
int front=,rear=;
while(front<rear){
state& s=st[front];
if(memcmp(goal,s,sizeof(s))==)return front; int z;
for(z=;z<;z++) if(!s[z]) break;
int x=z/,y=z%;
for(int d=;d<;d++){
int newx=x+dx[d];
int newy=y+dy[d];
int newz=newx*+newy;
if(newx>=&&newx<&&newy>=&&newy<){
state& t=st[rear];
memcpy(&t,&s,sizeof(s));//Copy
t[newz]=s[z];
t[z]=s[newz];
dis[rear]=dis[front]+;
if(try_to_insert(rear)) rear++;
}
}
front++;
}
return ;
} int main(){
// freopen("01.in","r",stdin);
string s;cin>>s;
for(int i=;i<=;i++)st[][i]=s[i]-''; int ans=bfs();
if(ans>) printf("%d\n",dis[ans]);
else printf("-1\n");
return ;
}

震惊!!!

判重三 //编码(只适用于码数很小的情况下,比如30!就不行)

代码

 #include<iostream>
#include<cstring>
#include<cstdio>
#include<set>//测试
#include<algorithm>
using namespace std;
typedef int state[]; state st[],goal={,,,,,,,,};
int dis[],dx[]={-,,,},dy[]={,,-,}; int vis[],fact[];
void init_lookup_table(){
fact[]=;
for(int i=;i<;i++) fact[i]=fact[i-]*i;
}
int try_to_insert(int s){
int code=;//把st[s]映射到整数code
for(int i=;i<;i++){
int cnt=;
for(int j=i+;j<;j++)if(st[s][j]<st[s][i]) cnt++;
code+=fact[-i]*cnt;
}
if(vis[code])return ;
return vis[code]=;
} int bfs(){
init_lookup_table();
int front=,rear=;
while(front<rear){
state& s=st[front];
if(memcmp(goal,s,sizeof(s))==)return front; int z;
for(z=;z<;z++) if(!s[z]) break;
int x=z/,y=z%;
for(int d=;d<;d++){
int newx=x+dx[d];
int newy=y+dy[d];
int newz=newx*+newy;
if(newx>=&&newx<&&newy>=&&newy<){
state& t=st[rear];
memcpy(&t,&s,sizeof(s));//Copy
t[newz]=s[z];
t[z]=s[newz];
dis[rear]=dis[front]+;
if(try_to_insert(rear)) rear++;
}
}
front++;
}
return ;
} int main(){
// freopen("01.in","r",stdin);
string s;cin>>s;
for(int i=;i<=;i++)st[][i]=s[i]-''; int ans=bfs();
if(ans>) printf("%d\n",dis[ans]);
else printf("-1\n");
return ;
}

总结起来就是:效率 hash>编码>set

另外这里有一个详细的转载:http://blog.csdn.net/ouxijv/article/details/7203027

洛谷 P1379 八数码难题 Label:判重&&bfs的更多相关文章

  1. 洛谷 P1379 八数码难题 解题报告

    P1379 八数码难题 题目描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中.要求解的问题是:给出一种初始布局(初 ...

  2. 洛谷——P1379 八数码难题

    P1379 八数码难题 双向BFS 原来双向BFS是这样的:终止状态与起始状态同时入队,进行搜索,只不过状态标记不一样而已,本题状态使用map来存储 #include<iostream> ...

  3. 洛谷P1379八数码难题

    题目描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中. 要求解的问题是:给出一种初始布局(初始状态)和目标布局(为 ...

  4. 洛谷—— P1379 八数码难题

    https://daniu.luogu.org/problem/show?pid=1379 题目描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示 ...

  5. 洛谷P1379 八数码难题

    传送门 1.先用dfs枚举9!的全排列,存到hash数组里(类似离散化),因为顺序枚举,就不需要排序了 2.朴素bfs,判重就用二分找hash:如果发现当前状态=要求状态,输出步数结束程序 上代码 # ...

  6. 洛谷 P1379 八数码难题

    题目描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中.要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了 ...

  7. 洛谷 - P1379 - 八数码难题 - bfs

    https://www.luogu.org/problemnew/show/P1379 #include <bits/stdc++.h> using namespace std; #def ...

  8. 洛谷 P1379 八数码难题 题解

    我个人感觉就是一道bfs的变形,还是对bfs掌握不好的人有一定难度. 本题思路: 大体上用bfs搜,用map来去重,在这里只需要一个队列,因为需要较少步数达到的状态一定在步数较多的状态之前入队列. # ...

  9. 洛谷 P1379 八数码难题(map && 双向bfs)

    题目传送门 解题思路: 一道bfs,本题最难的一点就是如何储存已经被访问过的状态,如果直接开一个bool数组,空间肯定会炸,所以我们要用另一个数据结构存,STL大法好,用map来存,直接AC. AC代 ...

随机推荐

  1. C/C++学习笔记---高地址、低地址、大段字节序、小段字节序

    字节顺序是指占内存多于一个字节类型的数据在内存中的存放顺序,通常有小端.大端两种字节顺序. 小端字节序指低字节数据存放在内存低地址处,高字节数据存放在内存高地址处: 大端字节序是高字节数据存放在低地址 ...

  2. EasyUi–7.tab和datagrid和iframe的问题

    1. 多个tab切换,第2个不显示 动态添加tab Iframe页面的方法 展开 折叠 <script type="text/javascript"> $(functi ...

  3. 图结构练习——最短路径(floyd算法(弗洛伊德))

    图结构练习——最短路径 Time Limit: 1000ms   Memory limit: 65536K  有疑问?点这里^_^ 题目描述  给定一个带权无向图,求节点1到节点n的最短路径.   输 ...

  4. [Win32命令行] 更改提示符字符串(PS1)

    当进入的目录比较深时, cmd的提示符几乎会占据整行, 很烦, 于是Google之... 参考: A better PROMPT for CMD.EXE ... 更改方式:        1. pro ...

  5. 修改了/etc/fstab之后出现登录密码输入之后又返回登录界面的问题

    最后那一个挂载到/home下面的盘是我新增加的,如果注释掉就一切正常,如果取消注释,就会发生标题说的问题. 后来我意思都这样直接挂载,导致/home下面原本的东西不在了,注释掉之后再来看,发现下面确实 ...

  6. Installing Hadoop on Mac OSX Yosemite Tutorial Part 1.

    Installing Hadoop on Mac OSX Yosemite Tutorial Part 1. September 23, 2014 Marek 68 Comments Install ...

  7. php 接受处理二进制数据流并保存成图片

    <form action="提交到处理地址" method="post" enctype="multipart/form-data" ...

  8. Windows Phone中获取UserAgent

    进入WP8时代后,通过DeviceExtendedProperties获取到的DeviceName不再是手机型号了,这对于需要获得手机型号做一些事情的应用(如新浪微博的小尾巴)来说,影响是比较大的. ...

  9. Windows phone 8.0 本地化遇到的两个问题

    基本上来说,按照msdn来讲的,本地化和全球化没有太多的问题,链接如下: http://msdn.microsoft.com/zh-cn/library/windowsphone/develop/ff ...

  10. 在ubuntu中安装maven

    安装环境 操作系统:ubuntu 14.04.1 server amd64 安装jdk 在安装maven之前,必须确保已经安装过jdk. 安装jdk的方法请参考文章<在ubuntu中安装jdk& ...