盼来盼去终于又要开始学习算法了!
笔者自学算法,所以学习顺序以个人舒服的形式!
用例子来看:
问题:
有一个迷宫,以1 2形式来表示————1表示是空地,即可以行走,2表示是障碍物,即无法通行。该迷宫由一个矩阵形式表示。
即
1 1 2 1
1 1 1 1
1 1 2 1
1 2 1 1
1 1 1 2
有终点和起点,我们需要计算从起点到达终点的最短路径!
准备代码为
int q,p,step;//(p,q)为终点坐标
int mmin=999999;
int a[100][100];//1表示空地//2表示障碍物
int v[100][100];//1表示访问//0表示未访问
解析代码为(优先理解该代码,方便后面理解)
void dfs(int x,int y,int step)
{
if(x==p&&y==q)
{
if(step<mmin)
mmin=step;
return;
}
//顺时针试探
//→
if(a[x][y+1]==1&&v[x][y+1]==0)
{
v[x][y+1]=1;
dfs(x,y+1,step+1);
v[x][y+1]=0;
}
//↓
if(a[x+1][y]==1&&v[x+1][y]==0)
{
v[x+1][y]=1;
dfs(x+1,y,step+1);
v[x+1][y]=0;
}
//←
if(a[x][y-1]==1&&v[x][y-1]==0)
{
v[x][y-1]=1;
dfs(x,y-1,step+1);
v[x][y-1]=0;
}
//↑
if(a[x-1][y]==1&&v[x-1][y]==0)
{
v[x-1][y]=1;
dfs(x-1,y,step+1);
v[x-1][y]=0;
}
return;
}
优化代码为
int dx[4]={0,1,0,-1};
int dy[4]={1,0,-1,0};
void dfs(int x,int y,int step)
{
if(x==p&&y==q)
{
if(step<mmin)
mmin=step;
return;
}
//顺时针试探
for(int k=0;k<=3;k++)
{
int tx,ty;
tx=x+dx[k];
ty=y+dy[k];
if(a[tx][ty]==1&&v[tx][ty]==0)
{
v[tx][ty]=1;
dfs(tx,ty,step+1);
v[tx][ty]=0;
}
}
return;
}
int main()
int main(int argc,char*argv[])
{
int m,n;
cin>>m>>n;
for(int i=1;i<=m;i++)
{
for(int j=1;j<=n;j++)
{
cin>>a[i][j];
}
}
int qi,z;
cin>>qi>>z>>p>>q;
v[qi][z]=1;
dfs(qi,z,0);
cout<<mmin;
return 0;
}
测试数据:
5 4
1 1 2 1
1 1 1 1
1 1 2 1
1 2 1 1
1 1 1 2
1 1 4 3
结果为7
理解:
之所以称之为宽度优先算法,是因为算法自始至终一直通过已找到和未找到顶点之间的边界向外扩展,就是说,算法首先搜索和s距离为k的所有顶点,然后再去搜索和S距离为k+l的其他顶点。
——取自百度百科
根据上文引用:“首先搜索和s距离为k的所有顶点,然后再去搜索和S距离为k+l的其他顶点”对此我们可以知道bfs与dfs不同的是bfs在行动时就已经开始在寻找不同路径,而dfs是只要找到了一条可通过则进行下一步步骤(因此dfs后面会出现回溯这一步)
可以举一个形象的例子,学校里举办寻宝活动,大家组队,因为学校特别大且道路特别多,所以找到宝藏点需要去探索。小A决定团体活动,大家一起行动,如果发现路不对,则一起再寻找其它路;而小B决定分开行动,大家走不同的路,总有一个人是正确的道路。显而易见从概率的角度分析,小B队伍获胜的概率远远大于小A;这里也可以相类似与dfs(小A)和bfs(小B).
解释结束,我们还是以迷宫问题为代表。
这里用到了queue。根据bfs定义可以很明显知道这里用queue比较适合
int a[100][100];
int v[100][100];
struct point {
int x;
int y;
int step;
};
queue<point> r;//申请队列
int dx[4] = { 0,1,0,-1 };
int dy[4] = { 1,0,-1,0 };
int main(int argc, char* argv[])
{
int n, m;
int st, end, p, q;
cin >> n >> m;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
cin >> a[i][j];
cin >> st >> end >> p >> q;
//bfs
point start;
start.x = st;
start.y = end;
start.step = 0;
r.push(start);//将起点入队
v[st][end] = 1;
int flag = 0;
while (!r.empty())
{
int x = r.front().x, y = r.front().y;
if (x == p && y == q)
{
flag = 1;
cout << r.front().step;
break;
}
for (int k = 0; k <= 3; k++)
{
int tx, ty;
tx = x + dx[k];
ty = y + dy[k];
if (a[tx][ty] == 1 && v[tx][ty] == 0)
{
point temp;
temp.x = tx;
temp.y = ty;
temp.step = r.front().step + 1;
r.push(temp);
v[tx][ty] = 1;
}
}
r.pop();//拓展完了需要将对首元素出队
}
if (flag == 0)
{
cout << "no ans";
}
return 0;
}