首页 > 编程语言 >图-C++基础

图-C++基础

时间:2024-10-19 21:49:06浏览次数:3  
标签:vector parent int 基础 C++ edge MAXN visited

图论是计算机科学和数学中非常重要的一个分支,涉及到图的性质、结构以及相关的算法。以下是对图论的基础知识、常用算法及其相关代码的整理,帮助你为CSP备考做好准备。

一、图的基本概念

1.1 图的定义

在数学中,图是一个由顶点(或节点)和边组成的集合。图可用以下形式表示:

  • 无向图:边没有方向,表示为 G(V,E),其中 V 是顶点集合, E 是边集合。
  • 有向图:边有方向,表示为有序对。

1.2 图的表示方式

  • 邻接矩阵:使用二维数组表示图,其中 matrix[i][j] 存储边 (i, j) 的权值(无边则为∞或0)。

    const int MAXN = 100; // 最大顶点数量
    int graph[MAXN][MAXN]; // 邻接矩阵

  • 邻接表:使用链表或向量表示图列表,适用于稀疏图。

    #include <vector>
    using namespace std;
    
    struct Edge {
        int to, weight;
    };
    
    vector<Edge> graph[MAXN]; // 邻接表

1.3 图的基本术语

  • 路径:顶点的有序序列,其中任何两顶点之间都有边连接。
  • 无环图:没有环的图(例如树)。
  • 连通图:对于任意两个顶点之间都有路径相连。
  • 强连通图:在有向图中,对于任意两个顶点 u 和 v, u 到 v 和 v 到 u 都有路径。

二、图的遍历

2.1 深度优先搜索 (DFS)

DFS 是一种用于遍历或搜索树或图的算法。其核心思想是尽可能深地搜索图的分支。

void DFS(int v, vector<bool> &visited) {
    visited[v] = true; // 标记为已访问
    // 访问该节点,比如输出其值
    for (auto &edge : graph[v]) {
        if (!visited[edge.to]) { // 如果未被访问
            DFS(edge.to, visited);
        }
    }
}

2.2 广度优先搜索 (BFS)

BFS 是一种基于队列的数据结构进行图的遍历。

#include <queue>

void BFS(int start) {
    queue<int> q;
    vector<bool> visited(MAXN, false);
    
    q.push(start);
    visited[start] = true;
    
    while (!q.empty()) {
        int v = q.front();
        q.pop();
        // 访问该节点,比如输出其值
        
        for (auto &edge : graph[v]) {
            if (!visited[edge.to]) {
                visited[edge.to] = true;
                q.push(edge.to);
            }
        }
    }
}

三、最短路径算法

3.1 Dijkstra 算法

用于找出非负权图中单源到所有其他顶点的最短路径。

#include <set>

void Dijkstra(int start) {
    vector<int> dist(MAXN, INT_MAX); // 初始化距离
    dist[start] = 0;
    set<pair<int, int>> s; // 维护一个集合用于寻找最小距离
    s.insert({0, start});
    
    while (!s.empty()) {
        int u = s.begin()->second; // 获取当前点
        s.erase(s.begin()); // 移除点
        
        for (auto &edge : graph[u]) {
            int v = edge.to;
            int weight = edge.weight;
            
            // 放松操作
            if (dist[u] + weight < dist[v]) {
                s.erase({dist[v], v});
                dist[v] = dist[u] + weight;
                s.insert({dist[v], v});
            }
        }
    }
}

3.2 Bellman-Ford 算法

用于找出含有负权边的图的单源最短路径。

void BellmanFord(int start) {
    vector<int> dist(MAXN, INT_MAX);
    dist[start] = 0;
    
    for (int i = 0; i < MAXN - 1; ++i) {
        for (auto &edge : all_edges) { // all_edges 是图中所有边的集合
            int u = edge.from;
            int v = edge.to;
            int weight = edge.weight;
            
            // 放松操作
            if (dist[u] != INT_MAX && dist[u] + weight < dist[v]) {
                dist[v] = dist[u] + weight;
            }
        }
    }
}

四、最小生成树

4.1 Prim 算法

用于找出无向连通图的最小生成树。

#include <vector>
#include <set>

void Prim(int start) {
    vector<int> key(MAXN, INT_MAX);
    vector<bool> inMST(MAXN, false);
    key[start] = 0;
    set<pair<int, int>> pq; // (权重, 顶点)
    pq.insert({0, start});
    
    while (!pq.empty()) {
        int u = pq.begin()->second;
        pq.erase(pq.begin());
        inMST[u] = true;
        
        for (auto &edge : graph[u]) {
            int v = edge.to;
            int weight = edge.weight;
            
            if (!inMST[v] && weight < key[v]) {
                pq.erase({key[v], v});
                key[v] = weight;
                pq.insert({key[v], v});
            }
        }
    }
}

4.2 Kruskal 算法

也是用于找出无向图的最小生成树,基于边的选择。

struct Edge {
    int u, v, weight;
};

bool cmp(Edge a, Edge b) {
    return a.weight < b.weight;
}

int find(int v, vector<int> &parent) {
    if (parent[v] != v) {
        parent[v] = find(parent[v], parent);
    }
    return parent[v];
}

void Kruskal() {
    vector<Edge> edges; // 存放所有边
    sort(edges.begin(), edges.end(), cmp);
    
    vector<int> parent(MAXN);
    for (int i = 0; i < MAXN; ++i) {
        parent[i] = i; // 初始化
    }
    
    for (auto &edge : edges) {
        int u = edge.u, v = edge.v;
        if (find(u, parent) != find(v, parent)) {
            parent[find(u, parent)] = find(v, parent); // 连接两个部分
            // 可以在这里记录选中的边
        }
    }
}

五、图的最大流问题

5.1 Ford-Fulkerson 算法

用于计算从源点到汇点的最大流。

#include <vector>
#include <queue>
#include <climits>

bool bfs(int s, int t, vector<vector<int>> &rGraph, vector<int> &parent) {
    vector<bool> visited(MAXN, false);
    queue<int> q;
    
    q.push(s);
    visited[s] = true;
    
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        
        for (int v = 0; v < MAXN; ++v) {
            if (!visited[v] && rGraph[u][v] > 0) { // 如果未访问且有残量
                q.push(v);
                visited[v] = true;
                parent[v] = u;
            }
        }
    }
    return visited[t]; // 返回汇点是否可达
}

int FordFulkerson(int s, int t) {
    vector<vector<int>> rGraph(MAXN, vector<int>(MAXN, 0));
    // rGraph[i][j] = originalCapacity[i][j];
    
    int max_flow = 0;
    vector<int> parent(MAXN);
    
    while (bfs(s, t, rGraph, parent)) {
        int path_flow = INT_MAX;
        for (int v = t; v != s; v = parent[v]) {
            int u = parent[v];
            path_flow = min(path_flow, rGraph[u][v]);
        }
        for (int v = t; v != s; v = parent[v]) {
            int u = parent[v];
            rGraph[u][v] -= path_flow;
            rGraph[v][u] += path_flow;
        }
        max_flow += path_flow;
    }
    return max_flow;
}

六、图的拓扑排序

拓扑排序用于有向无环图(DAG)的节点排序,使得每个有向边 u→v,u 在前,v 在后。

#include <algorithm>
#include <vector>

void topologicalSortUtil(int v, vector<bool> &visited, stack<int> &Stack) {
    visited[v] = true;
    for (auto &edge : graph[v]) {
        if (!visited[edge.to]) {
            topologicalSortUtil(edge.to, visited, Stack);
        }
    }
    Stack.push(v);
}

void topologicalSort() {
    stack<int> Stack;
    vector<bool> visited(MAXN, false);
    
    for (int i = 0; i < MAXN; ++i) {
        if (!visited[i]) {
            topologicalSortUtil(i, visited, Stack);
        }
    }
    
    while (!Stack.empty()) {
        cout << Stack.top() << " ";
        Stack.pop();
    }
}

七、常见的图论

问题

7.1 判断图的连通性

可以通过 DFS 或 BFS 来检查图是否连通。

7.2 图的最小路径问题

使用 Dijkstra 或 Bellman-Ford 算法来求解。

7.3 找出图中的桥

使用 DFS 进行 DFS 遍历,并记录时间戳,判断边是否为桥。

void findBridgesUtil(int u, vector<int> &disc, vector<int> &low, vector<bool> &visited, int parent) {
    visited[u] = true;
    disc[u] = low[u] = ++time;

    for (auto &edge : graph[u]) {
        int v = edge.to;

        if (!visited[v]) {
            findBridgesUtil(v, disc, low, visited, u);
            low[u] = min(low[u], low[v]);

            if (low[v] > disc[u]) {
                cout << "Bridge found: " << u << " - " << v << endl;
            }
        } else if (v != parent) {
            low[u] = min(low[u], disc[v]);
        }
    }
}

八、总结

以上是图论的基本概念、算法及其实现方法,涵盖了常见的图论知识点。这些内容对于理解和解决图论相关问题非常重要,在 C++ 程序设计和竞赛中,图论是一个必不可少的部分。

标签:vector,parent,int,基础,C++,edge,MAXN,visited
From: https://blog.csdn.net/weixin_73139914/article/details/143025925

相关文章

  • 【Java基础】物理内存&虚拟内存
    前言在Java程序运行过程中,操作系统为其分配了物理内存和虚拟内存。理解这两者的概念有助于明晰内存管理和性能优化。一、物理内存物理内存是指计算机的实际RAM(随机存取存储器)。Java进程在运行时需要向操作系统请求内存资源,操作系统通过分配物理内存来满足Java进程的内存......
  • Python基础入门
    目录1.简介2.安装与设置2.1检查是否已安装Python2.2使用Python解释器2.3使用代码编辑器3.Python基础语法3.1注释3.2变量和数据类型3.3输入输出3.4基本运算4.条件语句与循环4.1条件判断4.2循环while循环for循环break与continue5.函数与模块5.1......
  • 【C++】原地逆置单链表(不开辟新的储存空间)
    首先看图例:创建一个单链表L,并用指针p指向需要逆置的第一个结点,s指向p的下一个。(这里s的作用是为了防止p后的结点丢失) 第一个结点逆置后成为最后一个,所以其后为NULL,即p->next=NULL(其他结点正常头插)用s指向了的p之后的结点,所以它们不会丢失。第一个结点接上后,p、s重新指向......
  • [Java基础] 异常处理机制
    往期回顾[Java基础]基本数据类型[Java基础]运算符[Java基础]流程控制[Java基础]面向对象编程[Java基础]集合框架[Java基础]输入输出流[Java基础]异常处理机制[Java基础]Lambda表达式目录什么是异常处理?异常分类检查型异常非检查型异常(UncheckedExcepti......
  • 2024-2025-1 20241316 《计算机基础与程序设计》第四周学习总结
    2024-2025-120241316《计算机基础与程序设计》第四周学习总结作业信息这个作业属于哪个课程2024-2025-1-计算机基础与程序设计这个作业要求在哪里2024-2025-1计算机基础与程序设计第四周作业这个作业的目标<学习门电路,组合电路,逻辑电路,冯诺依曼结构,CPU,内存,IO管......
  • 文件系统基础
    初识文件系统文件是以硬盘位载体存储在计算机上的信息集合,在系统运行时,计算机以进程为基本单位进行资源的调度与分配而在用户进行的输入、输出中,则以文件为基本单位。这就需要操作系统有一个文件管理系统。操作系统的文件管理系统需要关心以下内容:计算机中存放了各种各样的文......
  • 【信奥赛·C++基础语法】CSP-J C++ STL 标准模板库 - 算法
    序言标准模板库(STL)的算法部分提供了一系列强大的工具,用于对各种容器中的数据进行操作。这些算法可以大大提高编程效率,减少代码重复,使程序更加简洁、高效和可读。无论是处理简单的数据结构还是复杂的大规模数据,STL算法都能发挥重要作用。一、STL算法的分类排序算法快速......
  • 2024-2025-1 20241319 《计算机基础与程序设计》第四周学习总结
    作业信息这个作业属于哪个课程2024-2025-1-计算机基础与程序设计这个作业要求在哪里https://www.cnblogs.com/rocedu/p/9577842.html#WEEK04这个作业的目标学习门电路,组合电路,逻辑电路,冯诺依曼结构,CPU,内存,IO管理,嵌入式系统,并行结构,物理安全作业正文https://www......
  • Midjourney零基础学习
    Midjourney学习笔记TOP13部分作品特色鲜明的艺术家、公司,以及有代表性的艺术风格。......
  • (新!)c++多态
    C++ 多态多态按字面的意思就是多种形态。当类之间存在层次结构,并且类之间是通过继承关联时,就会用到多态。C++多态意味着调用成员函数时,会根据调用函数的对象的类型来执行不同的函数。下面的实例中,基类Shape被派生为两个类,如下所示:实例#include<iostream>usingnames......