题目链接: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; }