图的学习.

本文发表于稀土掘金,csdn,个人blog:https://blog.loveoi.net/OI/数据结构/course-day-8/

什么是图

图是描述物件之间的关系。
物件就是结点,物件之间的关系即是边。

所以我们可以发现几乎所有的关系都可以表示成图,dp可以表示成DAG(有向无环图),搜索本质上是图的遍历算法,树也是特殊的图……

且图的存在也是非常重要的,很多问题都需要图的解决,比如导航就可以用图实现。

图的储存方式

图有多种储存方式,比如邻接矩阵,比如用vector。

邻接矩阵

定义 m a p [ u ] [ v ] map[u][v] map[u][v] (map是c++关键字)表示u和v节点直接有一条边。

空间复杂度为 O ( n 2 ) O(n^{2}) O(n2),在 n < = 1 0 3 n<=10^3 n<=103的时候适用。

举个例子,现在输入2个人,他们是朋友,最后统计每个人有多少个朋友。

我们可以定义 w [ 1 e 3 + 5 w[1e3+5 w[1e3+5][1e3+5]来存储2个人是否为朋友,遍历 w [ i ] [ 1   n ] w[i][1~n] w[i][1 n]即可判断是否为朋友。

这样我们就用实现了 O ( n ) O(n) O(n)输入, O ( n ) O(n) O(n)查询。

#include <bits/stdc++.h>
using namespace std;

bool w[1005][1005];  // w[x][y]: x 与 y 是否为朋友
int n, m;


void input() {
    cin >> n >> m;
    for(int i=1; i<=m; i++) {
        int u, v;
        cin >> u >> v;

        // u, v 是朋友
        w[u][v] = 1;        // v 是 u 的朋友
        w[v][u] = 1;        // u 是 v 的朋友
    }
}

// 统计 x 有多少个朋友
int getCnt(int x) {
    // 枚举每一个人,判断他是否为 x 的朋友
    int res = 0;

    for(int i=1; i<=n; i++)
        if(w[x][i]) res++;
    return res;
}

void work() {
    for(int i=1; i<=n; i++)
        cout << getCnt(i) << endl;
}

int main() {
    input();
    work();

    return 0;
}

vector存图

vector存图可能是用的最多的了,有的人喜欢用链式前向星来存图,但实际上vector就是在做链式前向星做的事。

对于每一个点,开一个vector存下他的边,空间复杂度: O ( m ) O(m) O(m),查询时间复杂度: O ( m ) O(m) O(m)是不是比邻接矩阵好多了?

当然当节点较少时还是邻接矩阵方便。

再将刚刚的问题用vector表示一下:

#include <iostream>
#include <vector>
using namespace std;
int n, m;
vector<int> e[100005];
int main()
{
    cin >> n >> m;
    for (int i = 1; i <= m; i++)
    {
        int u, v;
        cin >> u >> v;
        e[u].push_back(v);
        e[v].push_back(u);
    }
    for (int i = 1; i <= n; i++)
        cout << e[i].size() << endl;
    return 0;
}

总结

邻接矩阵:用 w [ u ] [ v ] w[u][v] w[u][v]存边权即可。
vector:需要写个结构体,来把邻居编号和边权打包起来;

邻接矩阵和vector存图的选择

图分为稀疏图和稠密图,当节点非常多,而边非常少的时候,他为稀疏图,反之则为稠密图。

因为vector没东西的时候几乎不用空间,所以我们可以选择vector,而当节点非常少,边非常多的时候我们就可以选择邻接矩阵存图。

有向图

刚刚我们为什么要把u和v都存一下对方呢?因为刚刚我们存储的是无向图,即两边都通,所以我们就需要把u和v都存一条通向对方的边。

有向图只需要只存一条边即可。

This post was written on Aug 16, 2022.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值