问题描述
我最近在研究 BFS 算法。我用这个算法做了一个迷宫求解程序。这是我的代码:
#include<iostream>
#include<cmath>
#include<sstream>
#include<vector>
#include<queue>
#include <unistd.h>
using namespace std;
int m,n;
inline int indexFor(int x,int y) {
return (x-1) + m*(y-1);
}
int main() {
FILE *file = fopen("test_case","r"); // test_case file
//build maze
fscanf(file,"%d",&m);
fscanf(file,&n);
vector<int> grid((m+1)*(n+1));
for(int i=1;i<=m;i++) {
for(int j =1;j<=n;j++) {
int k;
fscanf(file,&k);
grid[indexFor(i,j)] = k;
}
}
int startX,startY,endX,endY;
fscanf(file,&startX);
fscanf(file,&startY);
fscanf(file,&endX);
fscanf(file,&endY);
//bfs starts
queue<int> x,y;
x.push(1);
y.push(1);
vector<int> visited((m+1)*(n+1),0);
vector<vector<int>> path_track((m+1)*(n+1),vector<int>(2,0));
while(x.size()>0) {
int k = x.front(),l = y.front();
x.pop();
y.pop();
visited[indexFor(k,l)]=1;
// this part for printing each steps
cout << "\033[2J\033[H";
cout << "queue size: " << x.size()<<endl;
for(int i=1;i<=m;i++) {
for(int j =1;j<=n;j++) {
if(visited[indexFor(i,j)]==1) cout << "* ";
else {
if(grid[indexFor(i,j)]==0) {
cout << ". ";
} else {
cout << "# ";
}
}
}
cout << endl;
}
usleep(10);
if(k-1>0) {
if(grid[indexFor(k-1,l)] != 1 && visited[indexFor(k-1,l)]!=1) {
x.push(k-1);
y.push(l);
path_track[indexFor(x.back(),y.back())] = {k,l};
}}
if((k+1)<=m) {
if(grid[indexFor(k+1,l)] != 1 && visited[indexFor(k+1,l)]!=1) {
x.push(k+1);
y.push(l);
//cout << "Path_track: "<<x.back() << "," << y.back() << " : " << k << "," << l <<endl;
path_track[indexFor(x.back(),l};
}}
if(l-1>0) {
if(grid[indexFor(k,l-1)] != 1 && visited[indexFor(k,l-1)]!=1) {
x.push(k);
y.push(l-1);
path_track[indexFor(x.back(),l};
}}
if(l+1<=n) {
if(grid[indexFor(k,l+1)] != 1 && visited[indexFor(k,l+1)]!=1) {
x.push(k);
y.push(l+1);
path_track[indexFor(x.back(),l};
}}
}
cout << "\033[2J\033[H";
vector<vector<int>> path;
path.push_back({endX,endY});
while(endX!=0&&endY!=0) {
int kx = endX,ky = endY;
endX = path_track[indexFor(kx,ky)][0];
endY = path_track[indexFor(kx,ky)][1];
path.push_back({endX,endY});
}
path.pop_back();
if(path[path.size()-1][0] == startX && path[path.size()-1][1] == startY)
{
for(vector<int> l:path) grid[indexFor(l[0],l[1])] = 8;
for(int i=1;i<=m;i++) {
for(int j =1;j<=n;j++) {
if(grid[indexFor(i,j)]==8) {
cout << "X ";
} else {
if(grid[indexFor(i,j)]==0) {
cout << ". ";
} else {
cout << "# ";
}
}
}
cout << endl;
}
} else {
cout << "No path found\n";
for(vector<int> l:path) grid[indexFor(l[0],j)]==0) {
cout << ". ";
} else {
cout << "# ";
}
}
}
cout << endl;
}
}
//cout<<path_track[indexFor(2,2)][0]<<","<<path_track[indexFor(2,2)][1]<<endl;
return 0;
}
我为这个问题制作了一个 maze_generator :
#include <iostream>
#include <vector>
using namespace std;
int m,int y) {
return m * (x-1) + (y-1);
}
int main() {
srand(time(nullptr));
FILE * f = fopen("test_case","w");
cin >> m;
cin >> n;
vector<int> grid(m*n,0);
fprintf(f,"%d %d\n",m,n);
for(int i = 0; i<grid.size();i++) {
int k = (rand()%7);
if(i == 0 || i==grid.size()-1 ) k = 0;
grid[i] = k<5?0:1;
}
grid[indexFor(m,n)] = 0;
for(int i = 1;i<=m;i++) {
for(int j = 1; j<=n;j++) {
cout << grid[indexFor(i,j)] << " ";
fprintf(f,"%d ",grid[indexFor(i,j)]);
}
cout<<endl;
fprintf(f,"\n");
}
fprintf(f,"1 1\n%d %d",n);
return 0;
}
生成了这个 test_case:
21 50
0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 1 1 0 1 0 0 0 1 0 0 0 0 0 0 1 0 0 1 0 0 0 1 0 0 0 1 1 1 0 0 1 0 1
0 0 0 1 0 0 0 0 0 0 1 0 0 1 0 0 0 1 0 0 0 1 1 1 0 0 1 0 1 0 0 0 1 0 0 0 1 0 1 1 0 0 0 1 0 1 0 0 0 0
1 1 1 0 0 1 0 1 0 0 0 1 0 0 0 1 0 1 1 0 0 0 1 0 1 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 1 0 0 0 1 1 0 0 0 0
0 1 0 1 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 1 0 0 0 1 1 0 0 0 0 1 0 1 1 0 1 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0
0 0 1 1 0 0 0 0 1 0 1 1 0 1 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 1 0 0 0 0 0 0 1 1 1 1 0 0 0
0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 1 0 0 0 0 0 0 1 1 1 1 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0
0 1 1 1 1 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 1 0 1 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 1 0 1 1 1 1 0 0 0 1 0 0 0 0 1 0
0 1 0 1 0 0 0 0 0 0 0 0 0 1 0 1 1 1 1 0 0 0 1 0 0 0 0 1 0 0 1 0 1 0 0 0 0 0 0 1 0 1 0 0 0 0 1 0 0 0
0 1 0 0 0 0 1 0 0 1 0 1 0 0 0 0 0 0 1 0 1 0 0 0 0 1 0 0 0 0 0 1 1 0 0 1 0 1 0 0 1 0 0 0 0 0 1 1 0 0
0 0 0 0 1 0 0 0 0 0 1 1 0 0 1 0 1 0 0 1 0 0 0 0 0 1 1 0 0 0 1 0 0 1 1 0 0 0 0 0 0 0 1 1 1 0 1 1 0 1
0 0 0 0 1 1 0 0 0 1 0 0 1 1 0 0 0 0 0 0 0 1 1 1 0 1 1 0 1 0 1 1 0 0 0 0 1 0 1 0 0 0 0 0 1 0 0 0 0 1
1 1 1 0 1 1 0 1 0 1 1 0 0 0 0 1 0 1 0 0 0 0 0 1 0 0 0 0 1 0 1 0 1 0 0 0 0 1 0 0 0 1 0 1 0 1 0 1 0 0
0 0 1 0 0 0 0 1 0 1 0 1 0 0 0 0 1 0 0 0 1 0 1 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0
0 1 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 1 1 0 0 0 1 0 0 0 1 0 0 0 0 0 0 1 0 1 0 1
1 0 1 0 0 0 0 0 1 1 0 0 0 1 0 0 0 1 0 0 0 0 0 0 1 0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 1 0 0 1 1
0 0 0 1 0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 1 0 0 1 1 0 0 0 1 1 0 0 0 1 1 1 1 0 0 1 0 0 0 0 0 0
0 0 1 1 0 0 1 1 0 0 0 1 1 0 0 0 1 1 1 1 0 0 1 0 0 0 0 0 0 1 0 1 0 0 0 0 1 0 0 0 0 0 1 1 1 0 0 0 0 0
0 1 0 0 0 0 0 0 1 0 1 0 0 0 0 1 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 1 0 0 0 0 0 1 1 1 0 0 0 0 0 0 1 0 0 1
1 1 1 0 0 0 0 0 0 0 1 0 0 0 0 0 1 1 1 0 0 0 0 0 0 1 0 0 1 1 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 1 0 1 0
0 0 0 0 1 0 0 1 1 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 1 0 1 1 1 0 0
1 1
21 50
在测试用例中,最后两行代表迷宫的起点和终点。对于迷宫,0 表示自由路径,1 表示墙壁。第一行表示迷宫的大小。
问题是,当我解决它时,对于这个特定的 test_case,队列大小跃升至 130k+。有什么我想念的吗?还是正常的?
解决方法
我解决了这个问题。看起来我需要使用另一个数组进行队列映射来检查一个点是否已经排队。这是最终的解决方案:
#include<iostream>
#include<cmath>
#include<sstream>
#include<vector>
#include<queue>
#include <unistd.h>
using namespace std;
int m,n;
inline int indexFor(int x,int y) {
return (x-1) + m*(y-1);
}
int main() {
FILE *file = fopen("test_case","r");
fscanf(file,"%d",&m);
fscanf(file,&n);
vector<int> grid((m+1)*(n+1));
for(int i=1;i<=m;i++) {
for(int j =1;j<=n;j++) {
int k;
fscanf(file,&k);
grid[indexFor(i,j)] = k;
}
}
int startX,startY,endX,endY;
fscanf(file,&startX);
fscanf(file,&startY);
fscanf(file,&endX);
fscanf(file,&endY);
queue<int> x,y;
x.push(1);
y.push(1);
vector<int> visited((m+1)*(n+1),0);
vector<int> queued((m+1)*(n+1),0); // <-- THIS IS WHAT I ADDED
vector<vector<int>> path_track((m+1)*(n+1),vector<int>(2,0));
while(x.size()>0) {
int k = x.front(),l = y.front();
x.pop();
y.pop();
visited[indexFor(k,l)]=1;
cout << "\033[2J\033[H";
cout << "queue size: " << x.size()<<endl;
for(int i=1;i<=m;i++) {
for(int j =1;j<=n;j++) {
if(visited[indexFor(i,j)]==1) cout << "* ";
else {
if(grid[indexFor(i,j)]==0) {
cout << ". ";
} else {
cout << "# ";
}
}
}
cout << endl;
}
usleep(10000);
if(k-1>0) {
if(grid[indexFor(k-1,l)] != 1 && visited[indexFor(k-1,l)]!=1&&!queued[indexFor(k-1,l)]) {
x.push(k-1);
y.push(l);
queued[indexFor(x.back(),y.back())] = 1;
path_track[indexFor(x.back(),y.back())] = {k,l};
}}
if((k+1)<=m) {
if(grid[indexFor(k+1,l)] != 1 && visited[indexFor(k+1,l)]!=1&&!queued[indexFor(k+1,l)]) {
x.push(k+1);
y.push(l);
//cout << "Path_track: "<<x.back() << "," << y.back() << " : " << k << "," << l <<endl;
path_track[indexFor(x.back(),l};
queued[indexFor(x.back(),y.back())] = 1;
}}
if(l-1>0) {
if(grid[indexFor(k,l-1)] != 1 && visited[indexFor(k,l-1)]!=1&&!queued[indexFor(k,l-1)]) {
x.push(k);
y.push(l-1);
path_track[indexFor(x.back(),y.back())] = 1;
}}
if(l+1<=n) {
if(grid[indexFor(k,l+1)] != 1 && visited[indexFor(k,l+1)]!=1&&!queued[indexFor(k,l+1)]) {
x.push(k);
y.push(l+1);
queued[indexFor(x.back(),y.back())] = 1;
path_track[indexFor(x.back(),l};
}}
}
cout << "\033[2J\033[H";
vector<vector<int>> path;
/*
for(int i=1;i<=m;i++) {
for(int j =1;j<=m;j++) {
cout << path_track[indexFor(i,j)][0] << "," << path_track[indexFor(i,j)][1]<< " ";
}
cout << endl;
}
*/
path.push_back({endX,endY});
while(endX!=0&&endY!=0) {
int kx = endX,ky = endY;
endX = path_track[indexFor(kx,ky)][0];
endY = path_track[indexFor(kx,ky)][1];
path.push_back({endX,endY});
}
path.pop_back();
if(path[path.size()-1][0] == startX && path[path.size()-1][1] == startY)
{
for(vector<int> l:path) grid[indexFor(l[0],l[1])] = 8;
for(int i=1;i<=m;i++) {
for(int j =1;j<=n;j++) {
if(grid[indexFor(i,j)]==8) {
cout << "X ";
} else {
if(grid[indexFor(i,j)]==0) {
cout << ". ";
} else {
cout << "# ";
}
}
}
cout << endl;
}
} else {
cout << "No path found\n";
for(vector<int> l:path) grid[indexFor(l[0],j)]==0) {
cout << ". ";
} else {
cout << "# ";
}
}
}
cout << endl;
}
}
//cout<<path_track[indexFor(2,2)][0]<<","<<path_track[indexFor(2,2)][1]<<endl;
return 0;
}