Tempter of the Bone II

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 98304/32768 K (Java/Others)
Total Submission(s): 1090    Accepted Submission(s): 272

Problem Description
The doggie found a bone in an ancient maze, which fascinated him a lot. However, when he picked it up, the maze was changed and the way he came in was lost.He realized that the bone was a trap, and he tried desperately to get out of this maze.

The maze was a rectangle with the sizes of N by M. The maze is made up of a door,many walls and many explosives. Doggie need to reach the door to escape from the tempter. In every second, he could move one block to one of the upper, lower, left or right neighboring blocks. And if the destination is a wall, Doggie need another second explode and a explosive to explode it if he had some explosives. Once he entered a block with explosives,he can take away all of the explosives. Can the poor doggie survive? Please help him.

 
Input
The input consists of multiple test cases. The first line of each test case contains two integers N, M,(2 <= N, M <= 8). which denote the sizes of the maze.The next N lines give the maze layout, with each line containing M characters. A character is one of the following:

'X': a block of wall; 

'S': the start point of the doggie; 

'D': the Door;

'.': an empty block;

'1'--'9':explosives in that block.

Note,initially he had no explosives.

The input is terminated with two 0's. This test case is not to be processed.

 
Output
For each test case, print the minimum time the doggie need to escape if the doggie can survive, or -1 otherwise.
 
Sample Input
4 4
SX..
XX..
....
1..D
4 4
S.X1
....
..XX
..XD
0 0
 
Sample Output
-1
9
 

分析:由题目可以得到这样一个状态:在某点(x,y)含有炸弹数num且炸毁过哪些墙(实际上我是错了几次才完事这个状态的)

如这组数据:

6 5
S.XX1
X.1X1
XX.X.
XXXXX
XXXXX
XXXDX

在(1,4)这个点含有炸弹数量为1的状态就有2种:1是炸墙(1,3)过去的,2事炸墙(2,3)过去的,不同的状态会导致不同的结果

所以用:vector<long long int>mark[MAX][MAX][MAX*MAX*9];//在i,j含有炸弹k时所炸过的墙,来记录,至于炸过的墙和拿过的炸弹(拿过了就不能再拿了,所以也要记录),在这里我用状态压缩来记录,用数的二进制表示中德0,1来表示否还是是,由于8*8的网格,恰好unsigned long long int 能表示

这题就是分析某点的状态和记录比较麻烦,其他都和一般的搜索一样

给几组数据:

6 5
S.XX1
X.1X1
XX.X.
XXXXX
XXXXX
XXXDX
2 6
S.1XXD
1..XXX
4 4
S1X1
XXXX
XXDX
XXXX
6 2
S1
..
1X
XX
XX
DX
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<queue>
#include<algorithm>
#include<map>
#include<vector>
#include<iomanip>
#define INF 99999999
using namespace std; const int MAX=8+10;
vector<long long int>mark[MAX][MAX][MAX*MAX*9];//在i,j含有炸弹k时所炸过的墙
char Map[MAX][MAX];
int n,m;
int dir[4][2]={0,1,0,-1,1,0,-1,0}; struct Node{
int x,y,num,time;
unsigned long long open;//表示已经炸过的墙(最多8*8位)
unsigned long long key;//表示已经取过的炸药位置(最多8*8)
Node(){}
Node(int X,int Y,int Num,int Time,unsigned long long Open,unsigned long long Key){
x=X,y=Y,num=Num;
time=Time,open=Open,key=Key;
}
bool operator<(Node const &a)const{
return time>a.time;
}
}start; bool check(Node &next){
int size=mark[next.x][next.y][next.num].size();
for(int i=0;i<size;++i){//判断在该位置拥有炸弹num的情况下炸过的墙是否一样
if(next.open == mark[next.x][next.y][next.num][i])return true;
}
return false;
} int BFS(){
priority_queue<Node>q;
Node oq,next;
q.push(start);
while(!q.empty()){
oq=q.top();
q.pop();
for(int i=0;i<4;++i){
next=Node(oq.x+dir[i][0],oq.y+dir[i][1],oq.num,oq.time+1,oq.open,oq.key);
if(next.x<0 || next.y<0 || next.x>=n || next.y>=m)continue;
if(Map[next.x][next.y] == 'X'){//该点是墙
int k=next.x*m+next.y;
if( !((next.open>>k)&1) )--next.num,++next.time;//是否已炸过
next.open|=((1ll)<<k);
}
if(Map[next.x][next.y]>='1' && Map[next.x][next.y]<='9'){//该点有炸药可取
int k=next.x*m+next.y;
if( !((next.key>>k)&1) )next.num+=Map[next.x][next.y]-'0';//是否已取过
next.key|=((1ll)<<k);
}
if(next.num<0 || check(next))continue;
mark[next.x][next.y][next.num].push_back(next.open);
if(Map[next.x][next.y] == 'D')return next.time;
q.push(next);
}
}
return -1;
} void Init(){
for(int i=0;i<n;++i){
for(int j=0;j<m;++j){
for(int k=0;k<=m*n*9;++k){
mark[i][j][k].clear();//初始化没炸过任何墙
}
}
}
} int main(){
while(cin>>n>>m,n+m){
Init();
memset(mark,-1,sizeof mark);
for(int i=0;i<n;++i)cin>>Map[i];
for(int i=0;i<n;++i){
for(int j=0;j<m;++j){
if(Map[i][j] == 'S')start=Node(i,j,0,0,0,0);
}
}
cout<<BFS()<<endl;
}
return 0;
}

hdu2128之BFS的更多相关文章

  1. 图的遍历(搜索)算法(深度优先算法DFS和广度优先算法BFS)

    图的遍历的定义: 从图的某个顶点出发访问遍图中所有顶点,且每个顶点仅被访问一次.(连通图与非连通图) 深度优先遍历(DFS): 1.访问指定的起始顶点: 2.若当前访问的顶点的邻接顶点有未被访问的,则 ...

  2. 【BZOJ-1656】The Grove 树木 BFS + 射线法

    1656: [Usaco2006 Jan] The Grove 树木 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 186  Solved: 118[Su ...

  3. POJ 3278 Catch That Cow(bfs)

    传送门 Catch That Cow Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 80273   Accepted: 25 ...

  4. POJ 2251 Dungeon Master(3D迷宫 bfs)

    传送门 Dungeon Master Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 28416   Accepted: 11 ...

  5. Sicily 1215: 脱离地牢(BFS)

    这道题按照题意直接BFS即可,主要要注意题意中的相遇是指两种情况:一种是同时到达同一格子,另一种是在移动时相遇,如Paris在(1,2),而Helen在(1,2),若下一步Paris到达(1,1),而 ...

  6. Sicily 1048: Inverso(BFS)

    题意是给出一个3*3的黑白网格,每点击其中一格就会使某些格子的颜色发生转变,求达到目标状态网格的操作.可用BFS搜索解答,用vector储存每次的操作 #include<bits/stdc++. ...

  7. Sicily 1444: Prime Path(BFS)

    题意为给出两个四位素数A.B,每次只能对A的某一位数字进行修改,使它成为另一个四位的素数,问最少经过多少操作,能使A变到B.可以直接进行BFS搜索 #include<bits/stdc++.h& ...

  8. Sicily 1051: 魔板(BFS+排重)

    相对1150题来说,这道题的N可能超过10,所以需要进行排重,即相同状态的魔板不要重复压倒队列里,这里我用map储存操作过的状态,也可以用康托编码来储存状态,这样时间缩短为0.03秒.关于康托展开可以 ...

  9. Sicily 1150: 简单魔板(BFS)

    此题可以使用BFS进行解答,使用8位的十进制数来储存魔板的状态,用BFS进行搜索即可 #include <bits/stdc++.h> using namespace std; int o ...

随机推荐

  1. hibernate错误提示

    2016-05-03 09:45:03,275 -- WARN  -- org.hibernate.internal.util.xml.DTDEntityResolver.resolveEntity( ...

  2. XPATH 注入的介绍与代码防御

    0x01 介绍 软件未正确对 XML 中使用的特殊元素进行无害化处理,导致攻击者能够在终端系统处理 XML 的语法.内容或命令之前对其进行修改.在 XML 中,特殊元素可能包括保留字或字符,例如“&l ...

  3. Windows不能再本地计算机启动Apache

    1.显示的错误如下: 2.解决的方法是: 在运行中切换到你的apache的bin目录下,执行httpd.exe,看有什么提示 3.根据错误提示,修改相应的信息,比如我的是ServerRoot must ...

  4. ExecuteReader

    最近在做winform的编程,想到一真没有使用过ExecuteReader.可能以前以后它的用户不大,或者 不大好用,故没有用过.今天在这里将学习记录写下来,供读者参考: 1.MSDN上说:Sends ...

  5. Android Broadcast管理

  6. WPF Window对象

    户通过窗口与 Windows Presentation Foundation (WPF) 独立应用程序进行交互.窗口的主要用途是承载可视化数据并使用户可以与数据进行交互的内容.独立 WPF 应用程序使 ...

  7. MyEclipse10

    1.配置tomcat Windows->Preferences->My Eclipse->Servers->Tomcat,对于64位操作系统而言,Tomcat home dir ...

  8. php100视频教程解压密码

    php100-75-vip.rar 解压密码:php100-18293-2938-2839-348-#php100-76_u.rar 解压密码:php100-18634-6254-1001-283-# ...

  9. 使用ListItem给DropDownList填充数据

    global::日积月累啥的啊.DBhelper db = new 日积月累啥的啊.DBhelper(); ListItem[] item=]; DataTable dt=db.GetDataTabl ...

  10. 如何在sourcetree 下提交代码到gerrit上

    gerrit的审核机制决定了提交到远程到代码并非远程master分支,而是/refs/for/master 分支,所以需要解决怎么在sourcetree下提交代码到/refs/for/master分支 ...