http://acm.hdu.edu.cn/showproblem.php?pid=2364
题意:从唯一的起点‘@’出发,输出到达边界的步数,如果不能到达,输出-1。每走下一步,优先选择转弯的方向,只能直走(两边都是障碍物)时,才选择直走方向,重点是,不能往回走。
判断能否下一步转弯的思路是:先将四个方向用0,1,2,3标记,如果当前步方向和下一步方向相等,当前步方向+1,方向-1,如果这两个方向上同时存在障碍物,说明只能直走,加入队列;如果当前步方向和下一步方向不相等时,直接加入队列。这道题我理解错一个地方,它走过的地方其实可以再走,只是,走过的方向不能再走,所以当我用二维数组标记该点是否走过时,是有问题滴,因为它直接就将四个方向都标记为已经走过,正解应该是,在二维基础上多加一维,用以标记该点的四个方向。
~~~这道题,为什么我先判断只能直走的情况,再判断转弯的情况呢~~因为我对 c++的优先队列并不熟悉,就在函数内部直接判断的时候模拟优先队列操作过程,如果不用优先队列,直接用if(nowq.father!=i)Q.push(nextq);会将除了往回走的方向以外的三个方向直接无序加入,而此题的要求是,优先转弯,不能转弯再直走。
ps:昨天本来想把这道题作为我的双十一大礼包的,结果写了一个下午,都没有写出来,自己好菜啊~~~
#include<stdio.h> #include<string.h> #include<queue> using namespace std; #define N 85 int map[N][N],mmin,flag,n,m,vis[N][N][4]; char str[N][N]; typedef struct node{ int x,y; int father;//记录方向 int step;//记录步数 }node; int bfs(int x,int y) { int k[4][2]={0,1,-1,0,0,-1,1,0}; int nx,ny,xi,yi,x1,y1,x2,y2; node nextq,nowq; memset(vis,0,sizeof(vis));//初始化标记数组 queue<node>Q; flag = 0;//标记是否能够成功到达 nowq.father = -1;//起点的方向是-1,区别其它点 nowq.x = x; nowq.y = y; nowq.step = 0;//初始化起点 vis[x][y][0]=1,vis[x][y][1]=1;//起点标记为已经走过 vis[x][y][2]=1,vis[x][y][3] = 1; Q.push(nowq);//将起点加入队列 while(!Q.empty()) { nowq = Q.front() ; Q.pop(); if(nowq.x == 0||nowq.y == 0||nowq.x == n-1||nowq.y == m-1)//到达出口 { if(str[nowq.x][nowq.y]!='#') flag = 1;//能够成功到达 return nowq.step ; } for(int i = 0; i < 4; i ++) { nx = nowq.x + k[i][0]; ny = nowq.y + k[i][1]; if(nx < 0||ny < 0||nx > n-1||ny > m-1||str[nx][ny]=='#'||vis[nx][ny][i]) continue; //不能越界,不能是墙,不能已经是访问过的点 nextq.x = nx; nextq.y = ny; nextq.father = i;//记录父点到当前点的方向 nextq.step = nowq.step + 1;//步数加1 if(nowq.father%2 == i%2) { if(nowq.father == i) { x1 = nowq.x + k[(i+1)%4][0]; y1 = nowq.y + k[(i+1)%4][1]; x2 = nowq.x + k[(i-1+4)%4][0]; y2 = nowq.y + k[(i-1+4)%4][1]; if(str[x1][y1]!='.'&&str[x2][y2]!='.')//如果当前位置左右两边都不能走即只能直走 { vis[nx][ny][i] = 1;//标记该方向为已经访问过 Q.push(nextq); } } } else { vis[nx][ny][i] = 1; Q.push(nextq); } } } return -1; } int main() { int t,i,j,x,y; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); memset(str,0,sizeof(str)); for(i = 0; i < n; i ++) { scanf("%s",str[i]); for(j = 0; j < m; j ++) { if(str[i][j] == '@')//找到起点,存入x,y. { x = i; y = j; } } } mmin = bfs(x,y);//返回步数 if(flag)//如果能到达出口。输出步数 printf("%d ",mmin); else printf("-1 "); //否则输出-1 } return 0; }