图的相邻矩阵存储法之图的深度遍历——大一自学算法

写给未来大二的自己:结合注释!结合注释!结合注释!别把今天理解完的代码第二天就看不懂了啊喂!

图就长这样 

//写在开头:图的相邻矩阵存储法中  1表示有边(有边=还有路可以到除这个点以外的别的点)
// 0表示自己到自己(即i=j),∞(正无穷)表示没有边
//先看main函数
//和《啊哈算法》有点不同的是书中的代码表示的图是一行一行遍历的,我出于习惯是一列一列遍历的
#include<stdio.h>
int book[101],sum,m,e[101][101];
void dfs(int cur)
{
	int i;
	printf("%d",cur);
	sum++;//每访问一个顶点sum就加1
	if(sum==m)
		return;//当sum=m(此列所有点都访问过了)就可以直接退出了这个单列循环

	for(i=1;i<=m;i++)//从一号顶点开始依次尝试,看哪些顶点与当前cur有边相连
	{//从图中可以看出与1有边的有2,3和5,走哪个呢,此时我们规定一个顺序,按1~n走,于是先走2
		//到了2发现接下来只能走4,接下来没有路了所以我们返回了刚刚出现多种路的分岔口
		//同理走1-3,3-5,接着1-5
		if(e[i][cur]==1&&book[i]==0)//不撞南墙(这里的南墙指的i=m时)不回头
		{
			book[i]=1;
			dfs(i);
		}
	}
	return;//深度优先一定要记得返回,一定要返回一定要返回,返回到分岔口才能再次开始
}

int main()
{
	int i,j,n,a,b;
	scanf("%d %d",&n,&m);//画一个n*m的图
	for(i=1;i<=n;i++)
		for(j=1;j<=m;j++)//这是在画图
			if(i==j) e[i][j]=0;//主对角线上都是0(自己到自己都是0)
	else e[i][j]=99999999;//其他地方先放上∞

	for(i=1;i<=m;i++)
	{
		scanf("%d %d",&a,&b);
		e[a][b]=1;//遍历m遍,将其中有边的用1覆盖之前的∞
		e[b][a]=1;
	}
	book[1]=1;//从一号顶点出发,标记1号顶点
	dfs(1);

	return 0;
}

输入与输出

看注释吧少女,是个菜狗都看得懂(没错就是我!)

别删book数组,虽然理解起来觉得没必要,但是一删就崩,我也不知道为什么。

还有深度优先一定要记得函数的返回(return;)这个很重要

接下来做一个题目深化一下

题目描述:有五个城市,它们之间的路程与能否通行看下图,从城市1到城市5的最短路径

 

先画出它的图

 

接下来就是绘制图,不能到达的用∞表示,能达到的标注路程,自己到自己为0

PS:出于二维数组的特性a[行][列],这幅图包括接下来的代码为横向深度遍历

#include<stdio.h>
int min=99999999,book[101],n,e[101][101];

void dfs(int cur,int dis)//cur是目前到达的城市,dis是已走路程
{
	int j;
	if(dis>min)  return;//如果当前走过的路程已经大于已有的最短路径就舍弃这条路
	//这个可以运算缩短时间,特别是对于有很多种路径的图(不是此题)
	if(cur==n)//如果到达目的地了
	{
		if(dis<min)
			min=dis;
		return;
	}
	for(j=1;j<=n;j++)
	{
		if(e[cur][j]!=99999999&&book[j]==0)//如果此路可走(e[cur][j]不等于正无穷)且此路没走过
		{
			book[j]=1;//标记此路
			dfs(j,dis+e[cur][j]);//接着走
			book[j]=0;//一条路走到黑后回来分岔口将分岔口的标记取消
		}
	}
	return;
}

int main()
{
	int i,j,m,a,b,c;
	scanf("%d %d",&n,&m);
	for(i=1;i<=n;i++)
		for(j=1;j<=m;j++)
			if(i==j)
				e[i][j]=0;
	else e[i][j]=99999999;
	for(i=1;i<=m;i++)
	{
		scanf("%d %d %d",&a,&b,&c);
		e[a][b]=c;//表示有一条路可以从城市a到城市b,并且路程为c
	}
	book[1]=1;//1号城市已经在路径中了
	dfs(1,0);
	printf("%d",min);
	return 0;
}

 输入:

5 8

1 2 2

1 5 10

2 3 3

2 5 7

3 1 4

3 4 4

4 5 5

5 3 3

输出:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值