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


  • 相关阅读:
    Linux基础命令
    python中eval的用法
    man命令手册打开以后的使用方法
    Sequel Pro(连接mysql数据库)的下载和使用
    pycharm里连接mysql
    python里的路径拼接
    第一个接口自动化框架atp
    使用yaml(yml)写用例
    计算机及Linux简介
    xpath和css selector
  • 原文地址:https://www.cnblogs.com/javawebsoa/p/3230759.html
Copyright © 2020-2023  润新知