这道题一开始做成dfs,求最短路径去了。后来发现要在t时刻时恰好到达,所以要用bfs。然后学到一个奇偶剪枝的技巧。
现假设起点为(sx,sy),终点为(ex,ey),给定t步恰好走到终点,
s |
||||
| |
||||
| |
||||
| |
||||
+ |
— |
— |
— |
e |
如图所示(“|”竖走,“—”横走,“+”转弯),易证abs(ex-sx)+abs(ey-sy)为此问题类中任意情况下,起点到终点的最短步数,记做step,此处step1=8;
s |
— |
— |
— |
|
— |
— |
+ |
||
| |
+ |
|||
| |
||||
+ |
— |
— |
— |
e |
如图,为一般情况下非最短路径的任意走法举例,step2=14;
step2-step1=6,偏移路径为6,偶数(易证);
推广之,若 t-[abs(ex-sx)+abs(ey-sy)] 结果为非偶数(奇数),则无法在t步恰好到达;
#include <iostream> #include <cmath> using namespace std; int vis[8][8]; char map[8][8]; int dx[]={0,0,1,-1}; int dy[]={1,-1,0,0}; int n,m,t,sx,sy,gx,gy,flag; #define judge(x,y) vis[x][y]==0&&map[x][y]!=‘X‘&&0<=x&&x<n&&0<=y&&y<m//一开始写成==‘.‘ 导致走不到(gx,gy)因为它是‘D’ void init() { flag=0; for(int i=0;i<n;i++) for(int j=0;j<m;j++) { vis[i][j]=0; cin>>map[i][j]; if(map[i][j]==‘S‘) { sx=i;sy=j; } if(map[i][j]==‘D‘) { gx=i;gy=j; } } } void bfs(int x,int y,int tt) { if(tt>t) return ;//剪枝 if(flag==1) return ; if(x==gx&&y==gy&&tt==t) { flag=1; } for(int i=0;i<4;i++) { int nx=x+dx[i]; int ny=y+dy[i]; if(judge(nx,ny)) { vis[nx][ny]=1; bfs(nx,ny,tt+1); vis[nx][ny]=0; } } } int main() { while(cin>>n>>m>>t) { if(n==0&&m==0&&t==0) break; init(); //奇偶剪枝***** int p=abs(sx-gx)+abs(sy-gy)+t; if(p%2==1||p-2*t>0) //if(abs(sx-gx)+abs(sy-gy)>t||(sx+gx+sy+gy+t)%2==1) cout<<"NO"<<endl; else { vis[sx][sy]=1;//没有记录(sx,sy)为已走过 WA了一次 bfs(sx,sy,0); if(flag) cout<<"YES"<<endl; else cout<<"NO"<<endl; } } return 0; }
反思:
①The input is terminated with three 0‘s. This test case is not to be processed 可以用 &&(n+m+k) 即n、m、k同时为0。
②#define judge(x,y) 里面 ,map[x][y]!=‘X‘,一开始写成==‘.‘, 导致走不到(gx,gy),因为它是‘D’。
③没有记录(sx,sy)为已走过 WA了一次
④p那个地方可能出现负的,所以用abs(sx-gx)+abs(sy-gy)和t相加而不是相减;
时间: 2024-10-06 13:12:05