深度搜索和广度搜索

这篇博客很早之前就写好了,但是一直没有发出来。。。。。。


在进行详细解说之前,我们需要先借用图的概念,图就是由一些小圆点(称为顶点)和连接这些小圆点的直线(称为边)组成的。如下图是由5个顶点(1,2,3,4,5)和5条边(1-2,1-2,1-4,2-5,3-4)组成的。

 

    现在我们从一号顶点开始遍历这个图,使用深度优先搜索来遍历这个图将会得到如下的结果:


使用深度优先搜索来遍历这个图的过程具体是:首先从一个未走到过的顶点作为起始顶点,比如以1号顶点作为起点。沿1号顶点的边去尝试访问其他走到过得顶点,首先访问2号顶点还没有走到过,于是来到2号顶点。再以2号顶点作为出发点继续尝试访问其他未走过的顶点,这样又来到了4号顶点,再以4号顶点作为出发点继续尝试访问其他未走到过的顶点。但是,此时沿4号顶点的边,已经不能访问到其他未走到过的顶点了,所以需要返回到2号顶点。返回到2号顶点后,发现沿2号顶点的边也不能再访问到其他未走到过的顶点。因此还需要继续返回到1号顶点。再继续沿1号顶点的边看看还能否访问到其他为走到过的顶点。此时又会来到5号顶点。到此,所有的顶点都走到了,遍历结束。

深度优先遍历的主要思想是:首先以一个未访问过的顶点作为起始顶点,沿当前顶点的边走到未访问过的顶点;当没有未访问过的顶点时,则回到上一个顶点,继续试探访问别的访问,知道所有的顶点都被访问过。显然,深度优先搜索的遍历先沿着图的某一条分支遍历直到末端,然后回溯,再沿着另一条进行同样的遍历,直到所有的顶点都被访问过为止。

在用深度优先搜索时,最常使用的方法是用一个二维数组e来存储。二维数组中的第i行第j列表示的就是顶点i到顶点j是否有边,1表示有边,∞表示没有边。这里我们将自己到自己设为0(即I=j),我们将这种存储的方法称为图的邻接矩阵存储法。

 

广度优先遍历的主要思想就是:首先以一个未被访问过得顶点作为起始顶点,访问其所有的相邻的顶点,然后对每个相邻的顶点,再访问他们相邻的未被访问过的顶点,直到所有的顶点都被访问过,遍历结束。广度优先遍历往往是要用到队列这个概念的。

 

深度优先搜索和广度优先搜索的区别:

例1:小哼和小哈一同坐飞机去旅游,他们现在位于1号城市,目标是5号城市,可是1号城市并没有5号城市的直航。不过小哼已经收集了很多航班的信息,吸纳子啊小哼希望找到一种乘坐方式,使得转机的次数最少,该如何解决?(题目来源于:阿哈雷写的《啊哈,算法!》)

下面分别用两种方式来解决这个问题:

深度优先搜索:

#include<stdio.h>

int e[100][100];
int book[100];
int min = 9999999;

int end; //结束的站点
int n;//n个城市


void dfs(int cur,int sum)
{
    int i;
    
    if(sum > min)
    {
        return;
    }
  
    if(cur == end)
    {
        if(sum < min)
        {
            min = sum;
        }
	return;
    }

    for(i = 0; i < n; i++)
    {
        if(book[i] == 0 && e[cur][i] != 99999999)
	{

            book[i] = 1;
	    dfs(i,sum+e[cur][i]);
	    book[i] = 0;
	}
    }

}
int main()
{
    int a;
    int b;
    int i;
    int j;
       int m;//m个航线
    int start;//开始的站点
   
    scanf("%d %d",&n,&m);
    printf("m = %d\n",m);
    scanf("%d %d",&start,&end);

    for(i = 0; i < n; i++)
    {
        for(j = 0; j < n; j++)
	{
	    if(i == j)
	    {
	        e[i][j] = 0;
	    }
	    else
	    {
	        e[i][j] = 99999999;
	    }
	}
    }//初始化数组

//获取两个站点之间的航线
    for(i = 0; i < m; i++)
    {
        scanf("%d %d",&a,&b);
	e[a][b] = 1;
	e[b][a] = 1;
    }

    book[start] = 1;
    dfs(start,0);
    printf("min = %d\n",min);
}

结果:



法二:广度优先搜索

#include<stdio.h>

struct queue
{
    int n;//城市次数
    int sum;//转机次数
};

int main()
{
    struct queue que[100];
    int e[100][100];
    int book[100];
    int n;
    int m;

    int start;
    int end;
    int flag;

    int i;
    int j;
    int a;
    int b;
    int head = 1;
    int tail = 1;

    scanf("%d %d",&n,&m);
    scanf("%d %d",&start,&end);

    for(i = 1; i <= n; i++)
    {
        for(j = 1; j <= n; j++)
	{
	    if(i == j)
	    {
	        e[i][j] = 0;
	    }
	    else
	    {
	        e[i][j] = 99999999;
	    }
	}
    }

    for(i = 1; i <= m; i++)
    {
        scanf("%d %d",&a,&b);
	e[a][b] = 1;
	e[b][a] = 1;
    }
     
    que[tail].n = start;
    que[tail].sum = 0;
    tail++;
 
    book[start] = 1;

    while(head < tail)
    {
        int cur = que[head].n;//当前的城市
	for(i = 1; i <= n; i++)
	{
     	    if(e[cur][i] != 99999999 && book[i] == 0)
	    {
	        que[tail].n = i;
		que[tail].sum =  que[head].sum + 1;
	
		tail++;
		book[i] = 1;
	    }
	    if(que[tail-1].sum == end)
	    {
	        flag = 1;
		break;
	    }
	}
	if(flag == 1)
	{
	    break;
	}
	head++;
    }
    printf("min = %d",que[tail-1].sum);
}

结果:



以上:我也不知道自己写了些啥?最近效率有点低。。。。。。。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值