Poj2946-The Warehouse(bfs+哈希)
题目我就不粘贴了。。。
题意:给出地图,最大8*8,出口用'E'表示,空地用'.'表示,数字表示此处有多少个箱子,主人公的起点应该是在有箱子的地方,他可以朝四个方向移动,但是只有两种方式
一种是他移动到的位置也是有箱子的地方,另一种是空地,此时他可以把他所处位置的箱子全部推倒,朝那个方向铺成一条线,相当于每个地方一个箱子,但是所铺的位置原来
必须是 '.',否则是不能移动。问主人公最少需要多少步才能到达出口。不能达到输出Impossible.
解析:这题难在保存状态,而不在搜索的过程,最多有64个格子,相当于64个数,那么我们可以考虑用哈希将这么多数哈希成一个值,如何哈希呢?我是给每个数乘上一个系数,
比如第一个数乘上1,第二个数乘上1+131,第3个数乘上1+131+131,依此下去,然后模上一个数,用链表保存哈希值和对应的结构体下标,因为可能会出现两种不同的
状态哈希成同一个值,所以保存结构体下标是为了比较整个状态(这种需要整体比较的情况很少),其实整个搜索的状态并不是很多,用用哈希,细点心基本就可以过了。
代码
#include<cstdio>
#include<cstring>
#include<string>
#include<iostream>
#include<sstream>
#include<algorithm>
#include<utility>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<cmath>
#include<iterator>
#include<stack>
using namespace std;
const int INF=1e9+;
const double eps=1e-;
const int mod=;
const int maxn=;
int N,bex,bey;
int dx[]={-,,,},dy[]={,-,,};
bool in(int x,int y){ return x>=&&x<N&&y>=&&y<N; }
structnode
{
char S[][]; //结构体保存整个图和人的坐标
int x,y;
}nod[maxn];
structHash
{
int v,nid,next; //保存哈希值,结构体下标,以及next指针
}ha[mod+maxn];
int f,r,hash_id; //队首队尾指针
int GetHash(char S[][])
{
int ret=,k=;
for(int i=;i<N;i++)
for(int j=;j<N;j++) //得到哈希值
{
if(S[i][j]>=''&&S[i][j]<='') ret+=(S[i][j]-'')*k;
else ret+=*k;
k+=;
}
return ret;
}
bool Same(int a,int b) //整个状态比较
{
if(nod[a].x!=nod[b].x) return false;
if(nod[a].y!=nod[b].y) return false;
for(int i=;i<N;i++)
for(int j=;j<N;j++) if(nod[a].S[i][j]!=nod[b].S[i][j]) return false;
return true;
}
bool Insert_Hash(int v,int nid)
{
int a=v%mod;
int p=ha[a].next;
while(p!=-)
{
if(ha[p].v==v&&Same(ha[p].nid,nid)) return false; //出现相同的状态
p=ha[p].next;
}
p=++hash_id; //增加节点
ha[p].v=v; ha[p].nid=nid;
ha[p].next=ha[a].next; ha[a].next=p; //前插法
return true;
}
bool check(node& t,int x,int y,int k) //检查能都铺
{ int step=t.S[x][y]-'';
if(step==) return false;
t.S[x][y]='.';
while(step--)
{
x+=dx[k];
y+=dy[k];
if(!in(x,y)||t.S[x][y]!='.') return false; //越界不行,不是'.'也不行
t.S[x][y]='';
}
return true;
}
void Print(node& t)
{
printf("%d %d\n",t.x,t.y);
for(int i=;i<N;i++) printf("%s\n",t.S[i]);
puts("=========");
}
bool AddNode(node& t,int k)
{
int x=t.x,y=t.y;
int nx=x+dx[k],ny=y+dy[k];
if(!in(nx,ny)) return false;
if(t.S[nx][ny]=='E') return true; //到达出口
node& tt=nod[r];
tt=t; tt.x=nx; tt.y=ny;
if(t.S[nx][ny]=='.')
{
if(!check(tt,x,y,k)) return false;
}
int a=GetHash(tt.S);
if(Insert_Hash(a,r)) r++; //添加到队尾
//Print(tt);
return false;
}
bool bfs()
{
int en=r;
while(f<en)
{
node& t=nod[f++];
for(int i=;i<;i++) if(AddNode(t,i)) return true;
}
return false;
}
int solve()
{
if(nod[].S[bex][bey]=='E') return ;
if(nod[].S[bex][bey]=='.') return -;
for(int i=;i<mod;i++) ha[i].next=-;
hash_id=mod-;
f=,r=;
int step=;
while(f<r)
{
step++;
if(bfs()) return step;
}
return -;
}
int main()
{
while(scanf("%d%d%d",&N,&bex,&bey)!=EOF)
{
if(!N&&!bex&&!bey) break;
nod[].x=--bex; nod[].y=--bey;
for(int i=;i<N;i++) scanf("%s",nod[].S[i]);
int ans=solve();
if(ans==-) printf("Impossible.\n");
else printf("%d\n",ans);
}
return ;
}
Poj2946-The Warehouse(bfs+哈希)的更多相关文章
- UVA 10651 Pebble Solitaire(bfs + 哈希判重(记忆化搜索?))
Problem A Pebble Solitaire Input: standard input Output: standard output Time Limit: 1 second Pebble ...
- poj 2432 Around the world bfs+哈希
由于每个点的状态包含走过来的距离,所以要存二维的状态,但是状态总量太多,所以可以用哈希来搞. 那么就是bfs最短路,哈希记录状态了. #include <iostream> #includ ...
- hdu1067-Gap(bfs+哈希)
Let's play a card game called Gap. You have 28 cards labeled with two-digit numbers. The first digit ...
- 【算法】BFS+哈希解决八数码问题
15拼图已经有超过100年; 即使你不叫这个名字知道的话,你已经看到了.它被构造成具有15滑动砖,每一个从1到15上,并且所有包装成4乘4帧与一个瓦块丢失.让我们把丢失的瓷砖“X”; 拼图的目的是安排 ...
- POJ-3131-Cubic Eight-Puzzle(双向BFS+哈希)
Description Let's play a puzzle using eight cubes placed on a 3 × 3 board leaving one empty square. ...
- codevs1004四子连棋[BFS 哈希]
1004 四子连棋 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题目描述 Description 在一个4*4的棋盘上摆放了14颗棋子,其中有7颗 ...
- HDU 1043 Eight 【经典八数码输出路径/BFS/A*/康托展开】
本题有写法好几个写法,但主要思路是BFS: No.1 采用双向宽搜,分别从起始态和结束态进行宽搜,暴力判重.如果只进行单向会超时. No.2 采用hash进行判重,宽搜采用单向就可以AC. No.3 ...
- LeetCode_算法及数据结构覆盖统计
[输入]共计151道题的算法&数据结构基础数据 (见附录A) [输出-算法]其中有算法记录的共计 97道 ,统计后 结果如下 top3(递归,动态规划,回溯) 递归 动态规划 回溯 BFS ...
- HDU 1067 Gap
HDU 1067 Gap Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) P ...
随机推荐
- hdu 2254 奥运
点击打开hdu 2254 思路: 矩阵乘法 分析: 1 题目给定一个有向图,要求t1-t2天内v1-v2的路径的个数 2 根据离散数学里面的可达矩阵的性质,我们知道一个有向图的邻接矩阵的前n次幂的和即 ...
- Java单元测试工具:JUnit4(一)(二)(三)(四)
Java单元测试工具:JUnit4(一)--概述及简单例子 Java单元测试工具:JUnit4(二)--JUnit使用详解 Java单元测试工具:JUnit4(三)--JUnit详解之运行流程及常用注 ...
- python3-day4(yield)
1.yield 迭代器是访问集合元素的一种方式.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退.另外,迭代器的一 ...
- 基础总结篇之中的一个:Activity生命周期
子曰:溫故而知新,能够為師矣.<論語> 学习技术也一样,对于技术文档或者经典的技术书籍来说,指望看一遍就全然掌握,那基本不大可能,所以我们须要常常回过头再细致研读几遍,以领悟到作者的思想精 ...
- Java第三周学习日记
Day01 1.线程 进程:进程就是正在运行的应用程序.进程负责了内存空间的划分. 线程:一个进程中的代码是由线程去执行的,线程也就是其中一个执行路径. 多线程:一个进程中有多个线程可以同时执行任务. ...
- AngularJS初步
AngularJS特点 遵循AMD规范 不需要操作节点 对于jquery,一般是利用现有完整的DOM,然后在这戏Dom的基础上进行二次调教了:而对于AngularJS等框架则是根据数据模型以及其对应用 ...
- SpinLock(自旋锁)
SpinLock(自旋锁) SpinLock 结构是一个低级别的互斥同步基元,它在等待获取锁时进行旋转. 在多核计算机上,当等待时间预计较短且极少出现争用情况时,SpinLock 的性能将高于其他类型 ...
- Material Design说明
原文链接: Material Design 引言 我们挑战自我,为用户创造了一种视觉语言,综合了好设计的经典原则,革新以及科技的可能性.这就是material design.这份说明是一个动态的文档, ...
- iOS开发-清理缓存功能的实现
移动应用在处理网络资源时,一般都会做离线缓存处理,其中以图片缓存最为典型,其中很流行的离线缓存框架为SDWebImage. 但是,离线缓存会占用手机存储空间,所以缓存清理功能基本成为资讯.购物.阅读类 ...
- window.open() | close()方法
Window对象的open()方法可以打开一个新的浏览器窗口(或标签页),window.open()载入指定的URL到新的或已存在的窗口中,返回代表那个窗口的window对象,它有4个可选的参数 1. ...