HDOJ 1180 诡异的楼梯 DFS

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1180

用DFS很容易超时,尽管题中已经考虑了剪枝,还是超了 1000MS,这题有BFS的高效解法,不过感觉时间限制太小了,1000MS就超了,上次做的题,用BFS 2000MS还能

AC啊,先上代码,思路:重点考虑到达楼梯周围四个点时候的楼梯方向和四个位置,依次枚举。

#include <iostream>
#include <string>
#include <cstdio>
#include <cmath>
#include <vector>
#include <algorithm>
#include <sstream>
#include <cstdlib>
#include <fstream>
using namespace std;
int dis(int a,int b,int x,int y){
	return abs(a-x)+abs(b-y);
}
char maze[25][25];
bool visit[25][25],flag;
int dir[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
int stairs;
int n,m,sx,sy,endx,endy,tsum,tmin;
void dfs(int sx,int sy){
	if(maze[sx][sy]=='T'){
		flag=1;
		if(tsum<tmin)tmin=tsum;
		return ;
	}
	if(maze[sx][sy]=='*')return ;
	
	if(sx<1||sx>m||sy<1||sy>n)return ;
	
	if(tsum>tmin)return ;
	
	
	
//	cout<<"sx: "<<sx<<" "<<"sy: "<<sy<<" "<<"tsum: "<<tsum<<endl;
	
	for(int i=0;i<4;i++)
	{
		if(sx+dir[i][0]<1||sx+dir[i][0]>m||sy+dir[i][1]<1||sy+dir[i][1]>n)continue;
		if(maze[sx+dir[i][0]][sy+dir[i][1]]=='*')continue;
		if(visit[sx+dir[i][0]][sy+dir[i][1]])continue; 
		
		if(dis(sx+dir[i][0],sy+dir[i][1],endx,endy)>dis(sx,sy,endx,endy))continue;
		//剪枝:如果方向背离目标,即距离变大,则剪掉 
		
		
		if(maze[sx+dir[i][0]][sy+dir[i][1]]=='.'||maze[sx+dir[i][0]][sy+dir[i][1]]=='T'){
			tsum++;
			visit[sx+dir[i][0]][sy+dir[i][1]]=1;
			dfs(sx+dir[i][0],sy+dir[i][1]);
			visit[sx+dir[i][0]][sy+dir[i][1]]=0;
			tsum--;
		}
		if(maze[sx+dir[i][0]][sy+dir[i][1]]=='|'||maze[sx+dir[i][0]][sy+dir[i][1]]=='-')
		{
			
				//考虑到达楼梯前的两种情况和四个方位			
				if(tsum%2==0&&stairs==1 || tsum%2==1&&stairs==0){
					if(i==0){     //楼梯在上方,此时为 ‘|’ 
						tsum++;
						visit[sx+dir[i][0]][sy+dir[i][1]]=1;
						visit[sx+dir[i][0]-1][sy+dir[i][1]]=1;
						dfs(sx+dir[i][0]-1,sy+dir[i][1]);
						visit[sx+dir[i][0]][sy+dir[i][1]]=0;
						visit[sx+dir[i][0]-1][sy+dir[i][1]]=0;
						tsum--;
					}
					if(i==1){   //楼梯在下方 
						tsum++;
						visit[sx+dir[i][0]][sy+dir[i][1]]=1;
						visit[sx+dir[i][0]+1][sy+dir[i][1]]=1;
						dfs(sx+dir[i][0]+1,sy+dir[i][1]);
						visit[sx+dir[i][0]][sy+dir[i][1]]=0;
						visit[sx+dir[i][0]+1][sy+dir[i][1]]=0;
						tsum--;
					}
					if(i==2){
						tsum+=2;
						visit[sx+dir[i][0]][sy+dir[i][1]]=1;
						visit[sx+dir[i][0]][sy+dir[i][1]-1]=1;
						dfs(sx+dir[i][0],sy+dir[i][1]-1);
						visit[sx+dir[i][0]][sy+dir[i][1]]=0;
						visit[sx+dir[i][0]][sy+dir[i][1]-1]=0;
						tsum-=2;
					}
					if(i==3){
						tsum+=2;
						visit[sx+dir[i][0]][sy+dir[i][1]]=1;
						visit[sx+dir[i][0]][sy+dir[i][1]+1]=1;
						dfs(sx+dir[i][0],sy+dir[i][1]+1);
						visit[sx+dir[i][0]][sy+dir[i][1]]=0;
						visit[sx+dir[i][0]][sy+dir[i][1]+1]=0;
						tsum-=2;
					}
				
				} 
				 //此时到达楼梯前,楼梯方向为‘-’ 
				else if(tsum%2==1&&stairs==1 ||tsum%2==0&&stairs==0 ){
					if(i==0){
						tsum+=2;
						visit[sx+dir[i][0]][sy+dir[i][1]]=1;
						visit[sx+dir[i][0]-1][sy+dir[i][1]]=1;
						dfs(sx+dir[i][0]-1,sy+dir[i][1]);
						visit[sx+dir[i][0]][sy+dir[i][1]]=0;
						visit[sx+dir[i][0]-1][sy+dir[i][1]]=0;
						tsum-=2;
					}
					if(i==1){
						tsum+=2;
						visit[sx+dir[i][0]][sy+dir[i][1]]=1;
						visit[sx+dir[i][0]+1][sy+dir[i][1]]=1;
						dfs(sx+dir[i][0]+1,sy+dir[i][1]);
						visit[sx+dir[i][0]][sy+dir[i][1]]=0;
						visit[sx+dir[i][0]+1][sy+dir[i][1]]=0;
						tsum-=2;
					}
					if(i==2){
						tsum++;
						visit[sx+dir[i][0]][sy+dir[i][1]]=1;
						visit[sx+dir[i][0]][sy+dir[i][1]-1]=1;
						dfs(sx+dir[i][0],sy+dir[i][1]-1);
						visit[sx+dir[i][0]][sy+dir[i][1]]=0;
						visit[sx+dir[i][0]][sy+dir[i][1]-1]=0;
						tsum--;
					}
					if(i==3){
						tsum++;
						visit[sx+dir[i][0]][sy+dir[i][1]]=1;
						visit[sx+dir[i][0]][sy+dir[i][1]+1]=1;
						dfs(sx+dir[i][0],sy+dir[i][1]+1);
						visit[sx+dir[i][0]][sy+dir[i][1]]=0;
						visit[sx+dir[i][0]][sy+dir[i][1]+1]=0;
						tsum--;
					}
				}
				
			
		}
		
	}
}
int main()
{
//	ifstream fin;
//	fin.open("aaa.txt");
	
	while(cin>>m>>n)
	{
		for(int i=1;i<=m;i++)
		{
			for(int j=1;j<=n;j++)
			{
				cin>>maze[i][j];
				if(maze[i][j]=='S'){
					sx=i;
					sy=j;
				}
				if(maze[i][j]=='|'){
					stairs=1;             //标记楼梯的方向 
				}
				if(maze[i][j]=='-'){
					stairs=0;
				}
				if(maze[i][j]=='T'){
					endx=i;
					endy=j;
				}
			}
		}
		memset(visit,0,sizeof(visit));
		flag=0;
		tsum=0,tmin=999999;
		visit[sx][sy]=1;
		dfs(sx,sy);
		if(flag)cout<<tmin<<endl;
		//else cout<<"no!"<<endl;
	}
	return 0;
}

来一个bfs+优先队列的解法,0MS,里面用到的是小堆优先队列:

#include <iostream>
#include <cstdio>
#include <queue>
using  namespace std;
 
struct Node {
    int x, y, step;
};
 
bool operator< ( Node n1, Node n2 ) {
    return n1.step > n2.step;
}
 
 
int n, m;
int dir[4][2] = { 0, 1, 1, 0, 0, -1, -1, 0 };
char mp[25][25];
bool mark[25][25];
Node _s;
void input() {
    int i, j;
    for( i=0; i<n; ++i ) scanf( "%s", mp[i] );
    for( i=0; i<n; ++i ) {
        for( j=0; j<n; ++j ) {
            if( mp[i][j] == 'S' ) {
                _s.x = i;
                _s.y = j;
                _s.step = 0;
            }
        }
    }
}
 
 
inline bool isBond( Node nd ) {
    if( nd.x < 0 || nd.y < 0 || nd.x >= n || nd.y >= m || mp[nd.x][nd.y] == '*' ) return 1;
    return 0;
}
 
 
int solve() {
    priority_queue<Node> Q;
    Node p, q;
    int i;
 
    Q.push( _s );
    memset(mark, 0, sizeof(mark) );
    mark[_s.x][_s.y] = 1;
    while( !Q.empty() ) {
        p = Q.top();
        Q.pop();
        if( mp[p.x][p.y] == 'T' ) return p.step; //1.放这里判断比放for里面保险,虽然多花了点时间。
        for( i=0; i<4; ++i ) {
            q.x = p.x + dir[i][0];
            q.y = p.y + dir[i][1];
            q.step = p.step + 1;                 //2.走完后步数马上加
            if( isBond( q ) || mark[q.x][q.y] ) continue;
            if( mp[q.x][q.y] == '.' || mp[q.x][q.y] == 'T' ) {
                Q.push( q );
                mark[q.x][q.y] = 1;              //3.每次push后,马上跟新mark
                continue;
            } else if( mp[q.x][q.y] == '|' ) {
                if( p.step % 2 == 1 && i % 2 == 1 ) q.step ++;
                if( p.step % 2 == 0 && i % 2 == 0 ) q.step ++;
            } else if( mp[q.x][q.y] == '-' ) {
                if( p.step % 2 == 1 && i % 2 == 0 ) q.step ++;
                if( p.step % 2 == 0 && i % 2 == 1 ) q.step ++;
            }
            q.x += dir[i][0];
            q.y += dir[i][1];
            if( isBond(q) || mark[q.x][q.y] ) continue;
            Q.push( q );
            mark[q.x][q.y] = 1;
        }
    }
    return -1;
}
 
 
int main() {
//  freopen( "c:/aaa.txt", "r", stdin );
    while( scanf("%d %d", &n, &m) == 2 ) {
        input();
        printf( "%d\n", solve() );
    }
    return 0;
}



你可能感兴趣的:(算法,搜索,迷宫,DFS,剪枝)