题目我就不粘贴了。。。

题意:给出地图,最大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+哈希)的更多相关文章

  1. UVA 10651 Pebble Solitaire(bfs + 哈希判重(记忆化搜索?))

    Problem A Pebble Solitaire Input: standard input Output: standard output Time Limit: 1 second Pebble ...

  2. poj 2432 Around the world bfs+哈希

    由于每个点的状态包含走过来的距离,所以要存二维的状态,但是状态总量太多,所以可以用哈希来搞. 那么就是bfs最短路,哈希记录状态了. #include <iostream> #includ ...

  3. hdu1067-Gap(bfs+哈希)

    Let's play a card game called Gap. You have 28 cards labeled with two-digit numbers. The first digit ...

  4. 【算法】BFS+哈希解决八数码问题

    15拼图已经有超过100年; 即使你不叫这个名字知道的话,你已经看到了.它被构造成具有15滑动砖,每一个从1到15上,并且所有包装成4乘4帧与一个瓦块丢失.让我们把丢失的瓷砖“X”; 拼图的目的是安排 ...

  5. 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. ...

  6. codevs1004四子连棋[BFS 哈希]

    1004 四子连棋   时间限制: 1 s   空间限制: 128000 KB   题目等级 : 黄金 Gold   题目描述 Description 在一个4*4的棋盘上摆放了14颗棋子,其中有7颗 ...

  7. HDU 1043 Eight 【经典八数码输出路径/BFS/A*/康托展开】

    本题有写法好几个写法,但主要思路是BFS: No.1 采用双向宽搜,分别从起始态和结束态进行宽搜,暴力判重.如果只进行单向会超时. No.2 采用hash进行判重,宽搜采用单向就可以AC. No.3 ...

  8. LeetCode_算法及数据结构覆盖统计

    [输入]共计151道题的算法&数据结构基础数据 (见附录A) [输出-算法]其中有算法记录的共计 97道 ,统计后 结果如下  top3(递归,动态规划,回溯) 递归 动态规划 回溯 BFS ...

  9. HDU 1067 Gap

    HDU 1067 Gap Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)   P ...

随机推荐

  1. usaco5.5-Hidden Passwords

    最小表示法,感觉可以做成个模板,第一次RE是因为字符串长度变2倍了而我把数组开小了 Executing...   Test 1: TEST OK [0.008 secs, 3760 KB]   Tes ...

  2. QA笑话----杂思

    QA工程师走进酒吧,要了一杯啤酒,要了0杯啤酒,要了999999999杯啤酒,要了一只蜥蜴,要了-1杯啤酒,要了一个sfdeljknesv,酒保从容应对,QA工程师 很满意.接下来,一名顾客来到了同一 ...

  3. 论 <%@taglib prefix="s" uri="/struts-tags" %> 的重要性

    前段时间在做项目的时候,碰到这个问题 结果是相应的内容显示不出来,原来是忘了这句很关键的引入:<%@taglib prefix="s" uri="/struts-t ...

  4. Query语句对系统性能的影响

    需求: 取出某个group(假设id为1)下的用户编号id,用户昵称(nick_name),并按照加入组的时间(user_group.gmt_create)来进行倒序排列,取出前20个 解决方案一: ...

  5. (转)Building MariaDB on Mac OS X using Homebrew

    https://kb.askmonty.org/en/building-mariadb-on-mac-os-x-using-homebrew/ Work has been done to provid ...

  6. iOS应用性能调优的25个建议和技巧【转】

    转载自:http://blog.jobbole.com/37984/ 首页 最新文章 资讯 程序员 设计 IT技术 创业 在国外 营销 趣文 特别分享 更多 > - Navigation -  ...

  7. My way to Python - Day012 - 消息中间件

    消息中间件介绍 消息中间件的概念 消息中间件是在消息传输过程中保存消息的容器.消息中间件在将消息从它的源中继到它的目标时充当中间人的作用.队列的主要作用是提供路由并保证消息的传递:如果发生消息接收者不 ...

  8. PL/SQL破解方法(不需要注册码)

    打开注册表在run下输入regedit删除1.HKEY_CURRENT_USER/Software/Allround Automations2.HKEY_CURRENT_USER/Software/M ...

  9. EF中加载实体的方式

    EF中的查询执行时机:1. foreach进行枚举2. ToArray.ToList.ToDictionary3. Linq的一些操作,如First.Any4. DbSet上的Load操作.DbEnt ...

  10. C#基本语句与C++区别

    条件语句必须为bool表达式 int a = 1; if(a) { ... } 在c++中可以,但c#报错 但 bool b = true;//不能写成b = 1了: if(b) { ... } 是可 ...