树与图的存储+图的宽度优先遍历+题目:图中点的层次

96 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第16天,点击查看活动详情

树与图的存储

树是一种特殊的图,一种无环连通图

图的分类:

  1. 有向图:边有方向
  2. 无向图:是一种特殊的有向图,比如a和b之间,可以建两条有向边,一条是a到b,一条b到a的边

有向图的存储

image.png

  1. 邻接矩阵
    1. 开一个二维数组即可,g[a, b]:存的a->b的一条边
    2. true:表示这条边存在
    3. false:表示这条边不存在
    4. 适合存储:稠密图
  2. 邻接表
    1. n个点就开n个单链表
    2. 每个点的单链表就是存的这个点可以走到哪个点

代码

#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 100010, M = N * 2;

int h[N], e[M], ne[M], idx; // e:存所有的结点的值; ne:存所有结点的next值是多少

// 插入一条a指向b的边,也就是在a对应的邻接表的表头插入b
void add(int a, int b)
{
    e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
	
int main()
{
    memset(h, -1, sizeof h); // 链表的初始化,将所有的头全部初始化为-1即可
    
}

题目

www.acwing.com/problem/con… image.png

相关概念

image.png

  1. 重边
  2. 自环

分析

image.png

  1. 边的长度是1,说明可以用bfs来求最短路

代码

#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 100010;

int n, m;
int h[N], e[N], ne[N], idx;
int d[N], q[N]; // d:距离; q:队列

void add(int a, int b)
{
    e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}

int bfs()
{
    int hh = 0, tt = 0; // 定义队头跟队尾
    q[0] = 1; // 第一个元素是1
    
    memset(d, -1, sizeof d); // 初始化距离,-1表示没有遍历过
    
    d[1] = 0; // 第一个点已经被遍历过了,所以更新为0
    
    // bfs框架
    while (hh <= tt)
    {
         int t = q[hh++]; // 取队头元素
         // 拓展队头的所有点
         for (int i = h[t]; i != -1; i = ne[i])
         {
             int j = e[i];
             if (d[j] == -1) // 说明没有被遍历过的话
             {
                 d[j] = d[t] + 1;
                 q[++tt] = j; // 放入队列
             }
               
         }
    }
    
    return d[n];
}

int main()
{
    cin >> n >> m;
    
    memset(h, -1, sizeof h);
    
    for (int i = 0; i < m; i++)
    {
        int a, b;
        cin >> a >> b;
        add(a, b);
    }
    
    cout << bfs() << endl;
    
    return 0;
}