题目:给定一个含0和-1的迷宫,其中0可以通过而-1不能。输出任意一种路径。
这题有DFS和BFS两种方式。
DFS很容易:如果回溯了,则一定是遇到了死路,那么之前回溯过的部分都可以被覆盖掉,而且同一步只会走到唯一的坐标上(否则一定回溯了),因此只要开一个res[i]数组表示第i步到达的坐标就可以了。
BFS一步会走至多4个点,因此我们可以参考链式前向星的存图方式,用一个数组pre[i][j]表示到达点(i,j)的点(到达某点的点是唯一的)。这样我们再递归的输出就可以了。
代码如下(附赠样例一组):
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<utility>
using namespace std;
typedef pair<int,int> pr;
queue<pr> Q;
struct yjx{
int x,y;
}res[100001],pre[1001][1001];
bool lipu = 1;
int n,m,judge[1001][1001],s[1001][1001],dx[] = {0,1,0,-1},dy[] = {1,0,-1,0};
void dfs(int nx,int ny,int ex,int ey,int cnt){
int i;
if(nx == ex && ny == ey){
res[cnt].x = ex,res[cnt].y = ey;
for(i = 1;i <= cnt;i++){
if(i != 1) printf("->");
//if(i % 5 == 1 && i != 1) printf("\n");
printf("(%d,%d)",res[i].x,res[i].y);
lipu = 0;
printf("\n");
}
return;
}
if(s[nx][ny] || judge[nx][ny]) return;
judge[nx][ny] = 1;
res[cnt].x = nx,res[cnt].y = ny;
if(nx < n) dfs(nx + 1,ny,ex,ey,cnt + 1);
if(ny < m) dfs(nx,ny + 1,ex,ey,cnt + 1);
if(nx > 1) dfs(nx - 1,ny,ex,ey,cnt + 1);
if(ny > 1) dfs(nx,ny - 1,ex,ey,cnt + 1);
}
void goodbye(int a,int b,int c,int d){
if(pre[a][b].x) goodbye(pre[a][b].x,pre[a][b].y,c,d);
printf("(%d,%d)",a,b);
if(a != c || b != d) printf("->");
lipu = 0;
}
void bfs(int nx,int ny,int ex,int ey,int cnt){
int i,x1,y1;
Q.push(make_pair(nx,ny));
judge[nx][ny] = 1;
while(!Q.empty()){
nx = Q.front().first,ny = Q.front().second;
if(nx == ex && ny == ey) goodbye(nx,ny,ex,ey);
Q.pop();
for(i = 0;i <= 3;i++){
x1 = nx + dx[i],y1 = ny + dy[i];
if(x1 >= 1 && x1 <= n && y1 >= 1 && y1 <= m && s[x1][y1] && !judge[x1][y1]){
Q.push(make_pair(x1,y1));
judge[x1][y1] = 1;
pre[x1][y1].x = nx,pre[x1][y1].y = ny;
}
}
}
}
int main(){
char ch[4];
int i,j,temp,nx,ny,ex,ey;
scanf("%d %d",&n,&m);
for(i = 1;i <= n;i++){
for(j = 1;j <= m;j++){
scanf("%d",&temp);
s[i][j] = temp;
}
}
scanf("%d %d %d %d",&nx,&ny,&ex,&ey);
/*scanf("%s",ch);
if(ch[0] == 'd' || ch[0] == 'D') dfs(nx,ny,ex,ey,1);
else{
if(ch[0] == 'b' || ch[0] == 'B') bfs(nx,ny,ex,ey,1);
else printf("???");
}*/
if(lipu) printf("no way");
return 0;
}
/*
5 9
0 -1 0 0 0 0 0 0 -1
0 0 0 0 -1 0 0 0 -1
-1 0 0 0 0 0 -1 -1 -1
0 0 -1 -1 0 0 0 0 0
0 0 0 0 0 0 0 -1 -1
1 1 4 9
*/
进阶问题:(洛谷P1328)输出所有的路线方案。
根据上一道题的分析,这个就很难再用BFS了,加上数据范围也不大,我们就直接DFS好了。
对于已经走过的,我们只用在目前判断不可通过就行了,路线之间无影响,因此我们大可以模仿全排列操作。
代码如下:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<utility>
using namespace std;
typedef pair<int,int> pr;
queue<pr> Q;
struct yjx{
int x,y;
}res[100001];
bool lipu = 1;
int n,m,judge[1001][1001],s[1001][1001],dx[] = {0,-1,0,1},dy[] = {-1,0,1,0};
void dfs(int nx,int ny,int ex,int ey,int cnt){
int i,x1,y1;
if(nx == ex && ny == ey){
for(i = 0;i < cnt;i++){
if(i) printf("->");
printf("(%d,%d)",res[i].x,res[i].y);
lipu = 0;
}
printf("\n");
return;
}
for(i = 0;i <= 3;i++){
x1 = nx + dx[i],y1 = ny + dy[i];
if(x1 > 0 && x1 <= n && y1 > 0 && y1 <= m && !judge[x1][y1] && s[x1][y1]){
judge[x1][y1] = 1;
res[cnt].x = x1,res[cnt].y = y1;
dfs(x1,y1,ex,ey,cnt + 1);
judge[x1][y1] = 0;
}
}
}
int main(){
int i,j,nx,ny,ex,ey;
scanf("%d %d",&n,&m);
for(i = 1;i <= n;i++){
for(j = 1;j <= m;j++){
scanf("%d",&s[i][j]);
}
}
scanf("%d %d %d %d",&nx,&ny,&ex,&ey);
res[0].x = nx,res[0].y = ny;
judge[nx][ny] = 1;
dfs(nx,ny,ex,ey,1);
if(lipu) printf("-1");
return 0;
}
(注:洛谷对这题的走法规定了优先级,我只是做一个提醒,具体顺序怎么操作,请读者自行研究)
Thank you for reading!