【图论】建图、图(含树)的存储与遍历

学习资料
1.B02 图的存储
2.图是如何存储的:BFS、DFS
3.算法讲解059【必备】建图、链式前向星


各种存图方式的区别

图片来自上述学习资料
image
这里主要推荐表格中的后两种存图方法,因为适用于各种图。
只有在需要对一个点的所有出边进行排序的场合下,使用vector存边排序更方便,其余情况vector存边与链式前向星功能一样。

vector邻接表存图(方便排序)

尤其适用于需要对一个点的所有出边进行排序的场合
模版如下

const int N = 节点数量; //vector邻接表存图不用预先定义边数M,因为vector会自动增长
vector<int> g[N]; //邻接表存图
int st[N]; //标记数组

void add(int a, int b) //添加一条边a->b
{
    g[a].push_back(b);
}

//多组测试数据清空邻接表写法
for (auto& x : g) x.clear();//清空邻接表
//for (vector<int>& x : g) x.clear();//auto也可显示写出
memset(st, 0, sizeof st);//清空标记数组

DFS遍历(vector邻接表)

//写法一
void dfs(int x)
{
    st[x] = 1;
    cout << x << ' ';
    for (int i = 0; i < g[x].size(); i++)
    {
        int y = g[x][i];//编号为x的结点第i条边通向编号为y的结点
        if (!st[y])
        {
            dfs(y);
        }
    }
}
//写法二
void dfs(int x)
{
    st[x] = 1; //标记编号为x的结点已经访问过
    cout << x << ' ';
    for (int &y : g[x]) //遍历点x所有出边所连的结点,y为结点编号
    {
        if (st[y]) continue;
        dfs(y);
    }
}

BFS遍历(vector邻接表)

//写法一
void bfs(int sx)
{
    queue<int> q;
    q.push(sx);
    st[sx] = 1;

    while (q.size())
    {
        int x = q.front();
        q.pop();
        cout << x << ' ';

        for (int i = 0; i < g[x].size(); i++)
        {
            int y = g[x][i];
            if (!st[y])
            {
                st[y] = 1;
                q.push(y);
            }
        }
    }
}
//写法二
void bfs(int sx)
{
    queue<int> q;
    q.push(sx);
    st[sx] = 1;

    while (q.size())
    {
        int x = q.front();
        q.pop();
        cout << x << ' ';

        for (int &y : g[x]) //遍历点t所有出边所连的结点,y为结点编号
        {
            if (st[y]) continue;
            st[y] = 1;
            q.push(y);
        }
    }
}

邻接表存图 例题1 P5318 【深基18.例3】查找文献

#include <algorithm>
#include <cstring>
#include <iostream>
#include <queue>
#include <vector>

using namespace std;

const int N = 1e5 + 10;

int n, m;
vector<int> e[N];
int st[N];

void add(int a, int b)
{
    e[a].push_back(b);
}

void dfs(int u)
{
    st[u] = 1;
    cout << u << ' ';
    for (int i = 0; i < e[u].size(); i++)
    {
        int j = e[u][i];
        if (!st[j])
        {
            dfs(j);
        }
    }
}

void bfs(int sx)
{
    queue<int> q;
    q.push(sx);
    st[sx] = 1;

    while (q.size())
    {
        int t = q.front();
        q.pop();
        cout << t << ' ';

        for (int i = 0; i < e[t].size(); i++)
        {
            int j = e[t][i];
            if (!st[j])
            {
                st[j] = 1;
                q.push(j);
            }
        }
    }
}

int main()
{
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    cin >> n >> m;
    while (m--)
    {
        int a, b;
        cin >> a >> b;
        add(a, b);
    }
    for (int i = 1; i <= n; i++) sort(e[i].begin(), e[i].end());
    dfs(1);
    cout << '\n';
    memset(st, 0, sizeof st);
    bfs(1);
    return 0;
}

邻接表存图 例题2 P3915 树的分解

// Problem: P3915 树的分解
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P3915
// Memory Limit: 125 MB
// Time Limit: 1000 ms

#include <algorithm>
#include <cstring>
#include <iostream>
#include <queue>
#include <vector>

using namespace std;
using i64 = long long;
using PII = pair<int, int>;

const int N = 1e5 + 10;

int n, k, res;
vector<int> g[N];
int cnt[N], st[N];

void add(int a, int b)
{
    g[a].push_back(b);
}

void dfs(int x)
{
    st[x] = 1;
    cnt[x] = 1;
    for (int& y : g[x])
    {
        if (!st[y])
        {
            dfs(y);
            cnt[x] += cnt[y];
        }
    }
    if (cnt[x] == k)
    {
        cnt[x] = 0;
        res++;
    }
}

void solve()
{
    for (auto& x : g) x.clear();
    memset(cnt, 0, sizeof cnt);
    memset(st, 0, sizeof st);
    res = 0;
    cin >> n >> k;
    for (int i = 0; i < n - 1; i++)
    {
        int a, b;
        cin >> a >> b;
        add(a, b), add(b, a);
    }
    if (n % k) cout << "NO" << '\n';
    else
    {
        dfs(1);
        cout << (res == n / k ? "YES" : "NO") << '\n';
    }
}

int main()
{
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int T;
    cin >> T;
    while (T--) solve();
    return 0;
}

链式前向星存图(不能排序)

// 对于每个点k,开一个单链表,存储k所有可以走到的点。h[k]存储这个单链表的头结点
int h[N], e[N], ne[N], idx;

// 添加一条边a->b
void add(int a, int b)
{
    e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}

// 初始化
idx = 0;
memset(h, -1, sizeof h);

DFS遍历板子(链式前向星)

int dfs(int x)
{
    st[x] = true; // st[u] 表示点u已经被遍历过
	cout << x << ' ';//输出DFS序列
    for (int i = h[x]; i != -1; i = ne[i])
    {
        int y = e[i];
        if (!st[y]) dfs(y);
    }
}

BFS遍历板子(链式前向星)

void bfs(int sx)//sx为起点
{
    queue<int> q;
    q.push(sx);
    st[sx] = 1;

    while (q.size())
    {
        int x = q.front();
        q.pop();
		cout << x << ' ';

        for (int i = h[x]; i != -1; i = ne[i])
        {
            int y = e[i];
            if (!st[y])
            {
                st[y] = 1;
                q.push(y);
            }
        }
    }
}
posted @ 2025-02-12 10:42  Tshaxz  阅读(83)  评论(0)    收藏  举报
Language: HTML