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