图的遍历(邻接表 | 链式前向星)

题目链接

传送门

先上题目(多多关注_qaq

题目描述

给出 NN 个点,MM 条边的有向图,对于每个点 vv ,求 A(v)A(v) 表示从点 vv 出发,能到达的编号最大 的点。

输入格式

11 行,22 个整数 N,MN,M

接下来 MM 行,每行2个整数 Ui,ViU_i,V_i ,表示边 (Ui,Vi)(U_i,V_i) 。点用 1,2,,N1,2,⋯,N 编号。

输出格式

NN 个整数 A(1),A(2),,A(N)A(1),A(2),,A(N)A(1),A(2),\cdots,A(N)A(1),A(2),⋯,A(N)

输入

4 3
1 2
2 4
4 3

输出

4 4 3 4

说明/提示

• 对于 6060 % 的数据,1NM1031≤N,M≤10^3 • 对于 100100 % 的数据,1NM1051≤N,M≤10^5

本人暴力枚举的时候,自己编译时,发现只有样例过了,自己编的数据一个都没

过(内心有点酸~~~),后来才发现其实是邻接表。

邻接矩阵

先引入一下邻接矩阵吧。!!!不是邻接表

对于一张图~~ 在这里插入图片描述

我们可以先弄一张表格,如下:

|0| 1 |1 | |--|--|--|--|--| | 1 | 0 |0|||| |1|0|0||

其中,第i行第j列 表示 第i个城市和第j个城市是否联通(1为是,0为否)

由此,我们可得知 邻接矩阵具有对称性


众所周知 邻接矩阵空间和时间复杂度都是 N2N^2

让我们想一个问题:如果n为 10710^7 呢?,那么将会有大量的空间被浪费。


邻接表

由此,神诞生了——邻接表~~~(此处省略巨多音效 )

尊称:链式前向星

简介:空间和时间复杂度就都是 MM。对于稀疏图来说,MM 要远远小于 N2N^2

假设有 NN个点,MM 条边

3 3 1 2 1 3 2 3

序号 head to next
2 2 0
3 3 1
0 3 0

可以发现,从第 ii 点开始遍历,就先找到 head[i]head[i] 的序号,再找到 to[head[i]]to[head[i]]

(为点 ii 可以到达的边的序号,接下来, ii 就变成 next[head[i]]next[head[i]] ,接着循坏

————(本人第一次做 TLETLE 了无数次_QAQ)

11 为栗子:先找到 head[1]head[1] ,值为 22 ,接着找到 to[2]to[2] ,值为 33 ,记录 11 可以到达 33 ,再找到 next[2]next[2] ,值为 11 ,然后找到 to[1]to[1] ,值为 22 ,记录 11 可以到达 22 ,最后找到 next[1]next[1] ,值为 00 ,结束遍历。

 1\therefore \ 1 可以到达 2,32,3

也可以用结构体存储 totonextnext 数组

void add(int a, int b)
{ //插入
    p++;
    t[p].next = head[a];
    head[a] = p;
    t[p].to = b;
}

上机程序片段

for(int i = head[x]; i; i = t[i].next)

请查阅 https://blog.csdn.net/vocaloid01/article/details/76576822

https://so.csdn.net/so/search/all?q=%E9%82%BB%E6%8E%A5%E8%A1%A8&t=all&p=1&s=0&tm=0&lv=-1&ft=0&l=&u=

vectorvector才是真正的神! ! !

相对于链式前向星,vectorvector 则更为简单。

定义

const int maxn = 1e5 + 99;
struct Edge
{
    int to, w;
};
vector<Edge> d[maxn];

初始化

for (int i = 0; i < maxn; i++)
    d[i].clear();

建图

//在点A和点B之间建立一条权值为K的有向边
d[A].push_back({B, k});

遍历

for (int i = 0; i < d[tmp].size(); i++)

主要思路

对于一个点j,只需要把与j链接的点 ii 感染 ans(ans) 注意是逆序,就不用判断了——QAQ 如果有强迫症的话,就用 mmax[x]=max(mmax[x],u);mmax[x]=max(mmax[x],u);

接下来就是 插入要反过来 便于感染

add(b,a);

然后从大的点i开始遍历,找到一个点 zz 开始感染(附值)——而如果有一个比点 ii 小的点 jj ,也找到了点 zz ,那就直接跳过(因为 i>ji>j节约时间

if (mmax[x])
    return;
mmax[x] = u;

在这里插入图片描述

AC codeAC \ code

#include <bits/stdc++.h>
using namespace std;
int n, m, a, b, x, y, c[100001], head[100001], mmax[100001], p;
struct abc
{
    int to, next;
} t[100001];
void dfs(int x, int u)
{ //深搜
    if (mmax[x])
        return;
    mmax[x] = u; //感染  mmax[x]=max(mmax[x],u);
    for (int i = head[x]; i; i = t[i].next)
    {
        dfs(t[i].to, u);
    }
}
void add(int a, int b)
{ //插入
    p++;
    t[p].next = head[a];
    head[a] = p;
    t[p].to = b;
}
int main()
{
    cin >> m >> n;
    for (int i = 1; i <= n; i++)
    {
        cin >> a >> b;
        add(b, a);
    }
    for (int u = m; u >= 1; u--)
    {              //重点:注意是逆向 后面就不用max()了————啊哈哈~
        dfs(u, u); //第二个u是用来感染的“病毒”
    }
    for (int i = 1; i <= m; i++)
        cout << mmax[i] << " ";
    //cout<<endl<<endl;
    //for(int i=1;i<=m;i++)printf("%3d. %3d %3d %3d\n",i,head[i],t[i].to,t[i].next);
    return 0;
}

THE END\mathcal{THE \ END}

posted @ 2021-01-19 08:27  蒟蒻orz  阅读(9)  评论(0编辑  收藏  举报  来源