hdu2128之BFS

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;
}


原文地址:https://www.cnblogs.com/javawebsoa/p/3230759.html