题意: 给定一个n*m的图,途中的’S’为起点,‘E’为终点。每次移动只能横向或纵向地移向最近的一个干净的点’.'或终点,'X’为脏的点。如果能到达终点,则输出步数最少并且字典序最小的路径(下移为D、左移为L、右移为R、上移为U)。否则输出-1。
曲折经历: 比赛时想的没有那么周到,用BFS+DFS,结构体里携带各种参数,并且实时传递移动路径,导致空间占用比较大,加上本来算法的效率就不高,所以WA的和TLE的次数累计到达了13发。最后各种修改,卡常1980ms极限AC。又因为参加过这个比赛和做过这个题目的人很少,我甚至找不到题解可以学习。所以自己又花了一个上午的时间研究,最后得出一个时间和空间以及代码长度都最优的代码(对我的能力而言)
最终思路:
BFS。 众所周知:一个图 + 起点到终点 + 最短路径 = BFS。定义一个结构体的队列,结构体node中只需携带某个点的坐标即可。定义vis[][] 避免重复访问。pre_x[][]、pre_y[][]。 因为广搜的特性,从某个点出发,最多可能有四个可达的目标点。而因为vis避免重复访问,每个点一定只能来自于一个点。所以定义两个数组来记录某一个干净的点的前驱节点的坐标。DFS。 用BFS一直搜索到终点,结束广搜。我们记录路径的方式是用两个pre数组记录前驱节点的坐标,并没有记录移动的方向。所以可以通过dfs从终点递推回起点,比较每个点与前驱节点的坐标关系,记录下移动方向。最后倒叙输出答案即可。 #include<bits/stdc++.h> using namespace std; const int N = 2e3 + 10; int n, m; int sx, sy, cnt; //sx\sy记录起点坐标。cnt为路径的字符个数 int pre[N][N]; int pre_x[N][N]; //记录前驱节点的坐标 int pre_y[N][N]; int vis[N][N]; //访问标记,避免重复访问 char G[N][N]; //存图 char ans[2 * N]; //记录路径 int dir[][2] = {{1, 0}, {0, -1}, {0, 1}, {-1, 0}}; char Dir[] = "DLRU"; struct node { int x, y;}; int check(int x, int y) { //检查移动后是否还在图的范围内 if(x < 1 || x > n || y < 1 || y > m) return 0; return 1; } void dfs(int x, int y) { //从终点推回起点,标出移动路径 if(x == sx && y == sy){ //回到起点,输出答案 cout << cnt << endl; for(int i = cnt - 1; i >= 0; i--) cout << ans[i]; return; } int prex = pre_x[x][y]; int prey = pre_y[x][y]; ans[cnt++] = Dir[pre[x][y]]; dfs(prex, prey); } void BFS() { queue<node> Q; Q.push({sx, sy}); vis[sx][sy] = 1; while(!Q.empty()) { node u = Q.front(); Q.pop(); if(G[u.x][u.y] == 'E') { //找到终点,dfs找到移动路径 dfs(u.x, u.y); return ; } for(int i = 0; i < 4; i++) { int nex = u.x + dir[i][0]; int ney = u.y + dir[i][1]; while(check(nex, ney)) { if(vis[nex][ney]) break; if(G[nex][ney] == '.' || G[nex][ney] == 'E'){ vis[nex][ney] = 1; pre[nex][ney] = i; pre_x[nex][ney] = u.x; pre_y[nex][ney] = u.y; Q.push({nex, ney}); break; //找到最近的第一个干净点,插入队列即可推出 } //干净点不一定相邻,可能隔着几个'X'才能到达,所以需要不断移动查找 nex += dir[i][0], ney += dir[i][1]; } } } cout << -1 << endl; } int main() { ios :: sync_with_stdio(false); cin.tie(0); cout.tie(0); cin >> n >> m; for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++) { cin >> G[i][j]; if(G[i][j] == 'S') sx = i, sy = j; } BFS(); return 0; }