• 图学习笔记


     1、邻接矩阵(vector二维数组)的DFS(递归实现)

    1. class Graph {
    2. public:
    3. Graph(int vertices);
    4. void addEdge(int from, int to);
    5. void DFS(int startVertex);
    6. private:
    7. int vertices;
    8. vectorint>> adjMatrix;
    9. vector<bool> visited;
    10. void DFSRecursive(int vertex);
    11. };
    12. Graph::Graph(int vertices) {
    13. this->vertices = vertices;
    14. adjMatrix.resize(vertices, vector<int>(vertices, 0));
    15. visited.assign(vertices, false);
    16. }
    17. // 无向图
    18. void Graph::addEdge(int from, int to) {
    19. adjMatrix[from][to] = 1;
    20. adjMatrix[to][from] = 1; // For undirected graph
    21. }
    22. void Graph::DFS(int startVertex) {
    23. for (int i = 0; i < vertices; i++) {
    24. visited[i] = false;
    25. }
    26. DFSRecursive(startVertex);
    27. // 确保每一个点都能被遍历到,包括孤立点
    28. for (int i = 0; i < vertices; i++) {
    29. if(visited[i] == 0)
    30. DFSRecursive(i);
    31. }
    32. }
    33. void Graph::DFSRecursive(int vertex) {
    34. visited[vertex] = true;
    35. cout << "Visited vertex: " << vertex << endl;
    36. for (int i = 0; i < vertices; i++) {
    37. if (adjMatrix[vertex][i] == 1 && !visited[i]) {
    38. DFSRecursive(i);
    39. }
    40. }
    41. }

      2、邻接表(vector实现)的DFS(栈实现)

    1. class Graph {
    2. public:
    3. Graph(int vertices);
    4. void addEdge(int from, int to);
    5. void DFS(int startVertex);
    6. private:
    7. int vertices;
    8. vectorint>> adjList;
    9. };
    10. Graph::Graph(int vertices) {
    11. this->vertices = vertices;
    12. adjList.resize(vertices);
    13. }
    14. // 邻接表,每行长度不一。无向图
    15. void Graph::addEdge(int from, int to) {
    16. adjList[from].push_back(to);
    17. adjList[to].push_back(from);
    18. }
    19. void Graph::DFS(int startVertex) {
    20. vector<bool> visited(vertices, false);
    21. stack<int> s;
    22. visited[startVertex] = true;
    23. s.push(startVertex);
    24. while (!s.empty()) {
    25. int vertex = s.top();
    26. s.pop();
    27. cout << "Visited vertex: " << vertex << endl;
    28. for (int neighbor : adjList[vertex]) {
    29. if (!visited[neighbor]) {
    30. visited[neighbor] = true;
    31. s.push(neighbor);
    32. }
    33. }
    34. }
    35. }

    3、邻接表(vector实现)的BFS(队列实现)

    1. class Graph {
    2. public:
    3. Graph(int vertices);
    4. void addEdge(int from, int to);
    5. void BFS(int startVertex);
    6. private:
    7. int vertices;
    8. vectorint>> adjList;
    9. };
    10. Graph::Graph(int vertices) {
    11. this->vertices = vertices;
    12. adjList.resize(vertices);
    13. }
    14. // 无向图
    15. void Graph::addEdge(int from, int to) {
    16. adjList[from].push_back(to);
    17. adjList[to].push_back(from);
    18. }
    19. void Graph::BFS(int startVertex) {
    20. vector<bool> visited(vertices, false);
    21. queue<int> q;
    22. visited[startVertex] = true;
    23. q.push(startVertex);
    24. while (!q.empty()) {
    25. int vertex = q.front();
    26. q.pop();
    27. cout << "Visited vertex: " << vertex << endl;
    28. for (int neighbor : adjList[vertex]) {
    29. if (!visited[neighbor]) {
    30. visited[neighbor] = true;
    31. q.push(neighbor);
    32. }
    33. }
    34. }
    35. }

    4、链式前向星DFS和BFS

    1. #include
    2. #include
    3. #include
    4. using namespace std;
    5. const int maxn = 100000; // 假定最大顶点数
    6. struct Edge {
    7. int to, w, next; // 终点,边权,同起点的上一条边的编号
    8. } edge[maxn]; // 边集
    9. int head[maxn]; // head[i],表示以i为起点的第一条边在边集数组的位置(编号)
    10. int cnt = 0; // 记录边的数量
    11. int n, m; // 顶点数和边数
    12. void init() {
    13. for (int i = 1; i <= n; i++) head[i] = -1;
    14. cnt = 0;
    15. }
    16. // 添加新边
    17. void add_edge(int u, int v, int w) {
    18. edge[cnt].to = v; // 终点
    19. edge[cnt].w = w; // 权值
    20. edge[cnt].next = head[u]; // 以u为起点上一条边的编号,也就是与这个边起点相同的上一条边的编号
    21. head[u] = cnt++; // 更新以u为起点上一条边的编号
    22. }
    23. void DFS(int startVertex) {
    24. vector<bool> visited(n + 1, false);
    25. stack<int> s;
    26. s.push(startVertex);
    27. visited[startVertex] = true;
    28. while (!s.empty()) {
    29. int vertex = s.top();
    30. s.pop();
    31. cout << "Visited vertex: " << vertex << endl;
    32. for (int j = head[vertex]; j != -1; j = edge[j].next) {
    33. int neighborVertex = edge[j].to;
    34. if (!visited[neighborVertex]) {
    35. s.push(neighborVertex);
    36. visited[neighborVertex] = true;
    37. }
    38. }
    39. }
    40. }
    41. void BFS(int startVertex) {
    42. vector<bool> visited(n + 1, false);
    43. queue<int> q;
    44. q.push(startVertex);
    45. visited[startVertex] = true;
    46. while (!q.empty()) {
    47. int vertex = q.front();
    48. q.pop();
    49. cout << "Visited vertex: " << vertex << endl;
    50. for (int j = head[vertex]; j != -1; j = edge[j].next) {
    51. int neighborVertex = edge[j].to;
    52. if (!visited[neighborVertex]) {
    53. q.push(neighborVertex);
    54. visited[neighborVertex] = true;
    55. }
    56. }
    57. }
    58. }
    59. int main() {
    60. cin >> n >> m;
    61. int u, v, w;
    62. init(); // 初始化
    63. for (int i = 1; i <= m; i++) // 输入m条边
    64. {
    65. cin >> u >> v >> w;
    66. add_edge(u, v, w); // 加边
    67. }
    68. int startVertex;
    69. cout << "Enter the starting vertex for DFS: ";
    70. cin >> startVertex;
    71. DFS(startVertex);
    72. cout << "Enter the starting vertex for BFS: ";
    73. cin >> startVertex;
    74. BFS(startVertex);
    75. return 0;
    76. }

    5、无向图中,DFS判断连通块数量

    1. void DFS() {
    2. vis.resize(vertices);
    3. vis.assign(vertices, 0);
    4. unlinked_part = 0; // unlinked_part记录连通块数量
    5. for (int i = 0; i < vertices; i++) {
    6. if (vis[i] == 0) {
    7. DFSRecursive(i);
    8. unlinked_part++;
    9. }
    10. }
    11. }
    12. void DFSRecursive(int start) {
    13. vis[start] = 1;
    14. for (int i = 0; i < vertices; i++) {
    15. if (adjMatrix[start][i] == 1 && !vis[i]) {
    16. DFSRecursive(i);
    17. }
    18. }
    19. }

    6、最小生成树

    连通的带权无向图称为连通网。 最小生成树(Minimum Cost Spanning Tree)是代价最小的连通网的生成树,即该生成树上的边的权值和最小。
        
    最小生成树的性质:
    必须使用且仅使用连通网中的n-1条边来联结网络中的n个顶点;
    不能使用产生回路的边;
    各边上的权值的总和达到最小。
    (1)Prim算法
    1. class Graph {
    2. int vertices;
    3. vectorint>> adjMatrix;
    4. mapint> ele1;
    5. map<int, string> ele2;
    6. vector<int> vis;
    7. struct Closeedge {
    8. int from;
    9. int lowcost;
    10. };
    11. public:
    12. Graph() {}
    13. void build_Graph() {
    14. int n;
    15. cin >> n;
    16. this->vertices = n;
    17. adjMatrix.resize(vertices, vector<int>(vertices, INF));
    18. string* e = new string[n];
    19. for (int i = 0; i < n; i++) {
    20. cin >> e[i];
    21. ele1[e[i]] = i; // 记录节点字符对应的下标
    22. ele2[i] = e[i]; // 记录下标对应的字符
    23. }
    24. int m;
    25. cin >> m;
    26. edgenum = m;
    27. for (int i = 0; i < m; i++) {
    28. string from, to;
    29. int value;
    30. cin >> from >> to >> value;
    31. addEdge(ele1[from], ele1[to], value);
    32. }
    33. }
    34. void addEdge(int from, int to,int value) {
    35. adjMatrix[from][to] = 1;
    36. adjMatrix[to][from] = 1;
    37. }
    38. int Min(vector vec) {
    39. int k = -1, minn = INF;
    40. for (int i = 0; i < vertices; i++) {
    41. if (minn > vec[i].lowcost && vec[i].lowcost > 0) {
    42. minn = vec[i].lowcost;
    43. k = i;
    44. }
    45. }
    46. return k;
    47. }
    48. void Prim(string u) {
    49. int start = ele1[u]; // start为起始节点的下标
    50. int totlowcost = 0; // 记录最小权值和
    51. vector<int> ans; // 记录被选节点
    52. map<int, int> ans_cost; // 记录最小生成树每条路径的权值
    53. vector closeedge(vertices); // 用于保存未选顶点的最小权值边closedge和这条边的另一个已选顶点
    54. for (int i = 0; i < vertices; i++) {
    55. closeedge[i] = { start, adjMatrix[start][i] }; // 初始化
    56. }
    57. closeedge[start].lowcost = 0;
    58. for (int i = 1; i < vertices; i++) {
    59. int k = Min(closeedge); // 选择当前已选节点到未选节点最小权值边对应的未选节点
    60. totlowcost += closeedge[k].lowcost;
    61. ans.push_back(k);
    62. ans_cost[k] = closeedge[k].lowcost;
    63. closeedge[k].lowcost = 0; // 已选顶点的最小权值边置0,后续将不再被选
    64. for (int j = 0; j < vertices; j++) {
    65. if (adjMatrix[k][j] < closeedge[j].lowcost) {
    66. closeedge[j] = Closeedge{ k, adjMatrix[k][j] }; // 更新未选顶点的最小权值边
    67. }
    68. }
    69. }
    70. cout << totlowcost << endl;
    71. for (int i = 0; i < vertices - 1; i++) {
    72. int k = ans[i];
    73. cout << ele2[closeedge[k].from] << " " << ele2[k] << " " << ans_cost[k] << endl;
    74. }
    75. }
    76. };

    (2)Kruscal算法

    1. class MFSet {
    2. int n;
    3. vector<int> fa;
    4. public:
    5. MFSet(int n) {
    6. this->n = n;
    7. fa.resize(n);
    8. for (int i = 0; i < n; i++)
    9. fa[i] = i;
    10. }
    11. int find(int k) {
    12. if (fa[k] != k) return fa[k] = find(fa[k]);
    13. else return k;
    14. }
    15. void concat(int i, int k) {
    16. fa[fa[i]] = fa[k];
    17. for (int i = 0; i < n; i++)
    18. find(i);
    19. }
    20. int check() {
    21. int che = fa[0];
    22. for (int i = 0; i < n; i++) {
    23. if (che != fa[i]) return 0;
    24. }
    25. return 1;
    26. }
    27. };
    28. class Graph {
    29. int vertices;
    30. int edgenum;
    31. vectorint>> adjMatrix;
    32. mapint> ele1;
    33. map<int, string> ele2;
    34. vector<int> vis;
    35. struct edge {
    36. int from;
    37. int to;
    38. };
    39. public:
    40. Graph() {}
    41. void build_Graph() {
    42. int n;
    43. cin >> n;
    44. this->vertices = n;
    45. adjMatrix.resize(vertices, vector<int>(vertices, INF));
    46. string* e = new string[n];
    47. for (int i = 0; i < n; i++) {
    48. cin >> e[i];
    49. ele1[e[i]] = i; // 记录节点字符对应的下标
    50. ele2[i] = e[i]; // 记录下标对应的字符
    51. }
    52. int m;
    53. cin >> m;
    54. edgenum = m;
    55. for (int i = 0; i < m; i++) {
    56. string from, to;
    57. int value;
    58. cin >> from >> to >> value;
    59. addEdge(ele1[from], ele1[to], value);
    60. }
    61. }
    62. void addEdge(int from, int to,int value) {
    63. adjMatrix[from][to] = 1;
    64. adjMatrix[to][from] = 1;
    65. }
    66. void find_min(int &a, int &b, vectorint>>& vis_adj) {
    67. int minn = INF;
    68. for (int i = 0; i < vertices; i++) {
    69. for (int j = i+1; j < vertices; j++) {
    70. if (minn > adjMatrix[i][j] && vis_adj[i][j] == 0) {
    71. minn = adjMatrix[i][j];
    72. a = i, b = j;
    73. }
    74. }
    75. }
    76. vis_adj[a][b] = 1;
    77. }
    78. void Kruscal(){
    79. vector ans; // 记录最小生成树上的每条路径
    80. vectorint>> vis_adj; // 记录图中哪些边被选入最小生成树
    81. vis_adj.resize(vertices, vector<int>(vertices,0));
    82. MFSet mfset(vertices); // 并查集,记录每个节点所在集合
    83. int totlowcost = 0;
    84. int t = edgenum;
    85. while (t--) {
    86. int u, v;
    87. find_min(u, v,vis_adj); // 寻找未被选的最小权值边
    88. if (mfset.find(u) != mfset.find(v)) { // 两个节点属于不同集合,该边选入最小生成树的路径中
    89. mfset.concat(u, v);
    90. ans.push_back({ u,v });
    91. totlowcost += adjMatrix[u][v];
    92. }
    93. if (mfset.check() == 1) break; // 判断是否全部节点都属于同一集合,若是,则最小生成树已生成
    94. }
    95. if (mfset.check() == 0) {
    96. cout << -1 << endl;
    97. }
    98. else {
    99. cout << totlowcost << endl;
    100. for (int i = 0; i < ans.size(); i++) {
    101. cout << ele2[ans[i].from] << " " << ele2[ans[i].to] << " " << adjMatrix[ans[i].from][ans[i].to] << endl;
    102. }
    103. }
    104. }
    105. };

    7、无向图DFS生成森林

    1. #include
    2. #include
    3. #include
    4. using namespace std;
    5. // 树节点
    6. struct treenode{
    7. int val;
    8. vector son; // 存儿子节点指针
    9. treenode(int n) { val = n; }
    10. };
    11. vector Root; // 存每棵树的树根
    12. class Graph {
    13. public:
    14. Graph(int vertices);
    15. void addEdge(int from, int to);
    16. void DFS();
    17. treenode* DFSRecursive(int vertex);
    18. private:
    19. int vertices;
    20. vectorint>> adjMatrix;
    21. vector<bool> visited;
    22. };
    23. Graph::Graph(int vertices) {
    24. this->vertices = vertices;
    25. adjMatrix.resize(vertices, vector<int>(vertices, 0));
    26. visited.assign(vertices, false);
    27. }
    28. // 无向图
    29. void Graph::addEdge(int from, int to) {
    30. adjMatrix[from][to] = 1;
    31. adjMatrix[to][from] = 1;
    32. }
    33. void Graph::DFS() {
    34. visited.assign(vertices, 0);
    35. for (int i = 0; i < vertices; i++) {
    36. if (visited[i] == 0) {
    37. treenode* root;
    38. root=DFSRecursive(i);
    39. Root.push_back(root);
    40. }
    41. }
    42. }
    43. treenode* Graph::DFSRecursive(int vertex) {
    44. visited[vertex] = true;
    45. treenode* p = new treenode{ vertex };
    46. for (int i = 0; i < vertices; i++) {
    47. if (adjMatrix[vertex][i] == 1 && !visited[i]) {
    48. p->son.push_back(DFSRecursive(i));
    49. }
    50. }
    51. return p;
    52. }
    53. void show_tree(treenode *p) {
    54. cout << p->val;
    55. for (int i = 0; i < p->son.size(); i++) {
    56. if(p != nullptr)
    57. show_tree(p->son[i]);
    58. }
    59. }
    60. int main() {
    61. int n, m;
    62. cin >> n >> m;
    63. Graph G(n);
    64. for (int i = 0; i < m; i++) {
    65. int u, v;
    66. cin >> u >> v;
    67. G.addEdge(u, v);
    68. G.addEdge(u, v);
    69. }
    70. G.DFS();
    71. for (int i = 0; i < Root.size(); i++) {
    72. show_tree(Root[i]);
    73. cout << endl;
    74. }
    75. return 0;
    76. }

    8、图的最短路径(迪杰斯特拉算法)

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #define INF 0x3f3f3f3f
    9. using namespace std;
    10. class Graph {
    11. int vertices;
    12. vectorint>> adjMatrix;
    13. mapint> ele1;
    14. map<int, string> ele2;
    15. vector<int> vis;
    16. public:
    17. Graph() {}
    18. void build_Graph() {
    19. int n;
    20. cin >> n;
    21. this->vertices = n;
    22. adjMatrix.assign(vertices, vector<int>(vertices));
    23. string* e = new string[n];
    24. for (int i = 0; i < n; i++) {
    25. cin >> e[i];
    26. ele1[e[i]] = i; // 记录节点字符对应的下标
    27. ele2[i] = e[i]; // 记录下标对应的字符
    28. }
    29. for (int i = 0; i < n; i++) {
    30. for (int j = 0; j < n; j++) {
    31. int tmp;
    32. cin >> tmp;
    33. addEdge(i, j, tmp);
    34. }
    35. }
    36. }
    37. void addEdge(int from, int to, int value) {
    38. adjMatrix[from][to] = value;
    39. }
    40. void Dijkstra() {
    41. vectorint>> path; // 记录起点到其他每个节点最短路径的路径
    42. path.resize(vertices);
    43. vis.assign(vertices, 0);
    44. vector<int> dis; // 记录起点到其他每个节点的最短路径距离
    45. dis.assign(vertices, INF);
    46. string start;
    47. cin >> start;
    48. int v = ele1[start];
    49. vis[v] = 1;
    50. dis[v] = 0;
    51. for (int i = 0; i < vertices; i++) {
    52. if(adjMatrix[v][i])
    53. {
    54. dis[i] = dis[v] + adjMatrix[v][i]; // 更新起点到其他点的最短路径距离
    55. path[i].push(v);
    56. }
    57. }
    58. for (int i = 0; i < vertices - 1; i++) {
    59. int Min = INF;
    60. for (int j = 0; j < vertices; j++)
    61. if (!vis[j] && Min > dis[j])
    62. {
    63. v = j;
    64. Min = dis[j];
    65. }
    66. vis[v] = 1;
    67. // 用当先被选中点来更新到最短路径距离
    68. for (int j = 0; j < vertices; j++) {
    69. if (!vis[j] && adjMatrix[v][j] && Min + adjMatrix[v][j] < dis[j]) {
    70. path[j] = path[v];
    71. path[j].push(v);
    72. dis[j] = Min + adjMatrix[v][j];
    73. }
    74. }
    75. }
    76. // 输出
    77. for (int i = 0; i < vertices; i++) {
    78. if (i != ele1[start]) {
    79. cout << start << "-" << ele2[i] << "-";
    80. if (dis[i] == INF) {
    81. cout << "-1" << endl;
    82. }
    83. else {
    84. cout << dis[i] << "----[";
    85. while(!path[i].empty()) {
    86. cout << ele2[path[i].front()] << " ";
    87. path[i].pop();
    88. }
    89. cout << ele2[i] << " ]" << endl;
    90. }
    91. }
    92. }
    93. }
    94. };
    95. int main() {
    96. int t;
    97. cin >> t;
    98. while (t--) {
    99. Graph G;
    100. G.build_Graph();
    101. G.Dijkstra();
    102. }
    103. }

    9、判断图上是否出现正环,即环上所有的边相乘大于1(货币套汇问题)

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #define INF 0x3f3f3f3f
    9. using namespace std;
    10. class Graph {
    11. int vertices;
    12. vectordouble>> adjMatrix;
    13. mapint> ele1;
    14. map<int, string> ele2;
    15. vector<int> vis;
    16. vectordouble>> check; // check记录从i到j节点路径权值的乘积
    17. int flag;
    18. public:
    19. Graph() {}
    20. void build_Graph() {
    21. int n;
    22. cin >> n;
    23. this->vertices = n;
    24. adjMatrix.assign(vertices, vector<double>(vertices, 0));
    25. int m;
    26. cin >> m;
    27. string* e = new string[n];
    28. for (int i = 0; i < n; i++) {
    29. cin >> e[i];
    30. ele1[e[i]] = i; // 记录节点字符对应的下标
    31. ele2[i] = e[i]; // 记录下标对应的字符
    32. }
    33. for (int i = 0; i < m; i++) {
    34. string from, to;
    35. double value;
    36. cin >> from >> value >> to;
    37. addEdge(ele1[from], ele1[to], value);
    38. }
    39. }
    40. void addEdge(int from, int to, double value) {
    41. adjMatrix[from][to] = value;
    42. }
    43. int DFS() {
    44. vis.assign(vertices, 0);
    45. for (int i = 0; i < vertices; i++) {
    46. for (int j = 0; j < vertices; j++) {
    47. if (i == j) check[i][j] = 1;
    48. else check[i][j] = 0;
    49. }
    50. }
    51. flag = 0;
    52. for (int i = 0; i < vertices; i++) {
    53. if (vis[i] == 0)
    54. DFSRecursive(i);
    55. if (flag == 1) return 1;
    56. }
    57. return 0;
    58. }
    59. void DFSRecursive(int vertex) {
    60. vis[vertex] = true;
    61. for (int i = 0; i < vertices; i++) {
    62. // adjMatrix[vertex][i] && vis[i] == 1 即表示存在环,
    63. // check[i][vertex] * adjMatrix[vertex][i]即从i到j节点路径权值的乘积*j到i权值的乘积 = 环上权值乘积
    64. if (adjMatrix[vertex][i] && vis[i]) {
    65. if (check[i][vertex] * adjMatrix[vertex][i] > 1) flag = 1;
    66. continue;
    67. }
    68. else if(adjMatrix[vertex][i]){
    69. for (int j = 0; j < vertices; j++) {
    70. check[j][i] = check[j][vertex] * adjMatrix[vertex][i];
    71. }
    72. DFSRecursive(i);
    73. }
    74. }
    75. }
    76. };
    77. int main() {
    78. int t;
    79. cin >> t;
    80. while (t--) {
    81. Graph G;
    82. G.build_Graph();
    83. if (G.DFS()) {
    84. cout << "YES" << endl;
    85. }
    86. else cout << "NO" << endl;
    87. }
    88. }

    10、键路径-STL版(含拓扑排序)

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #define INF 0x3f3f3f3f
    9. using namespace std;
    10. class Graph {
    11. int vertices;
    12. vectorint>> adjMatrix;
    13. vector<int> ve; // 记录顶点的最早开始时间
    14. vector<int> vl; // 记录顶点的最晚开始时间
    15. stack<int> st_re; // 存AOE图的拓扑序列
    16. queue<int> q; // 用于处理AOE图的拓扑序列
    17. vector<int> init; // 记录节点入度
    18. public:
    19. Graph() {}
    20. void build_Graph() {
    21. int n;
    22. cin >> n;
    23. this->vertices = n;
    24. adjMatrix.assign(vertices, vector<int>(vertices, 0));
    25. init.assign(vertices, 0);
    26. int m;
    27. cin >> m;
    28. for (int i = 0; i < m; i++) {
    29. int u, v, e;
    30. cin >> u >> v >> e;
    31. adjMatrix[u][v] = e;
    32. init[v]++;
    33. }
    34. }
    35. void Topoorder() {
    36. for (int i = 0; i < vertices; i++) {
    37. if (init[i] == 0) q.push(i);
    38. }
    39. ve.assign(vertices, 0);
    40. while (!q.empty()) {
    41. int w = q.front();
    42. st_re.push(w);
    43. q.pop();
    44. for (int i = 0; i < vertices; i++) {
    45. if (adjMatrix[w][i] != 0) {
    46. init[i]--;
    47. if (init[i] == 0) q.push(i);
    48. if (ve[w] + adjMatrix[w][i] > ve[i]) ve[i] = ve[w] + adjMatrix[w][i];
    49. }
    50. }
    51. }
    52. // 输出每个顶点的最早开始时间
    53. for (int i = 0; i < vertices; i++) {
    54. cout << ve[i] << " ";
    55. }
    56. cout << endl;
    57. }
    58. void CriticalPath() {
    59. vl.assign(vertices, ve[st_re.top()]); // ***注意:vl的初始化是用拓扑排序的最后一个顶点的ve值做初始化,而非
    60. // 用ve[vertices - 1]做初始化,节点vertices - 1不一定为拓扑排序的最
    61. // 后一个顶点,即不一定为AOE网的终点
    62. while (!st_re.empty()) {
    63. int w = st_re.top();
    64. st_re.pop();
    65. for (int i = 0; i < vertices; i++) {
    66. if (adjMatrix[i][w] != 0) {
    67. if (vl[w] - adjMatrix[i][w] < vl[i]) vl[i] = vl[w] - adjMatrix[i][w];
    68. }
    69. }
    70. }
    71. // 输出每个顶点的最迟开始时间
    72. for (int i = 0; i < vertices; i++) {
    73. cout << vl[i] << " ";
    74. }
    75. cout << endl;
    76. // 输出关键路径
    77. for (int i = 0; i < vertices; i++) {
    78. if (i == vertices - 1) cout << i << endl;
    79. if (ve[i] == vl[i] && i < vertices - 1) cout << i << "->";
    80. }
    81. }
    82. };
    83. int main() {
    84. Graph G;
    85. G.build_Graph();
    86. G.Topoorder();
    87. G.CriticalPath();
    88. }

    11、旅游规划

    有了一张自驾旅游路线图,你会知道城市间的高速公路长度、以及该公路要收取的过路费。现在需要你写一个程序,帮助前来咨询的游客找一条出发地和目的地之间的最短路径。如果有若干条路径都是最短的,那么需要输出最便宜的一条路径。

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #define INF 0x3f3f3f3f
    9. using namespace std;
    10. class Graph {
    11. int vertices;
    12. struct vec{
    13. int wag;
    14. int charge;
    15. };
    16. vector> adjMatrix;
    17. vector<int> vis;
    18. int start, end;
    19. public:
    20. Graph() {}
    21. void build_Graph() {
    22. int n;
    23. cin >> n;
    24. this->vertices = n;
    25. adjMatrix.assign(vertices, vector(vertices, {0,0}));
    26. int m;
    27. cin >> m;
    28. cin >> start >> end;
    29. for (int i = 0; i < m; i++) {
    30. int u, v, w, c;
    31. cin >> u >> v >> w >> c;
    32. addEdge(u, v, w, c);
    33. }
    34. }
    35. void addEdge(int from, int to, int w, int c) {
    36. adjMatrix[from][to].wag = w;
    37. adjMatrix[from][to].charge = c;
    38. }
    39. void Dijkstra() {
    40. vector<int> charge;
    41. charge.assign(vertices, 0);
    42. vis.assign(vertices, 0);
    43. vector<int> dis;
    44. dis.assign(vertices, INF);
    45. int v = start;
    46. vis[v] = 1;
    47. dis[v] = 0;
    48. charge[v] = 0;
    49. for (int i = 0; i < vertices; i++) {
    50. if(adjMatrix[v][i].wag)
    51. {
    52. dis[i] = dis[v] + adjMatrix[v][i].wag;
    53. charge[i] += adjMatrix[v][i].charge;
    54. }
    55. }
    56. for (int i = 0; i < vertices - 1; i++) {
    57. int Min = INF;
    58. for (int j = 0; j < vertices; j++)
    59. if (!vis[j] && Min > dis[j])
    60. {
    61. v = j;
    62. Min = dis[j];
    63. }
    64. vis[v] = 1;
    65. int tmpcharge;
    66. for (int j = 0; j < vertices; j++) {
    67. tmpcharge = INF;
    68. if (!vis[j] && adjMatrix[v][j].wag && Min + adjMatrix[v][j].wag <= dis[j]) {
    69. if (Min + adjMatrix[v][j].wag == dis[j] && charge[v] + adjMatrix[v][j].charge < tmpcharge) tmpcharge = charge[v] + adjMatrix[v][j].charge;
    70. dis[j] = Min + adjMatrix[v][j].wag;
    71. }
    72. if(tmpcharge != INF) charge[j] = tmpcharge;
    73. }
    74. }
    75. cout << dis[end] << " " << charge[end];
    76. }
    77. };
    78. int main() {
    79. Graph G;
    80. G.build_Graph();
    81. G.Dijkstra();
    82. }

    12、拯救007(坐标转为图节点)

    将坐标轴上的点看作图的节点,将岸上坐标、鳄鱼坐标和岛上中心看作节点,看能否从岛上中心的节点遍历到岸上节点,若可,即可以逃脱

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #define INF 0x3f3f3f3f
    10. using namespace std;
    11. class Graph {
    12. int vertices;
    13. vectorint>> adjMatrix;
    14. struct Node {
    15. int x, y;
    16. Node() {}
    17. Node(int xx, int yy) { x = xx, y = yy; }
    18. };
    19. vector<int> vis;
    20. int D;
    21. vector node;
    22. int flag;
    23. public:
    24. Graph() {}
    25. void build_Graph() {
    26. int n;
    27. cin >> n;
    28. this->vertices = n + 1;
    29. adjMatrix.assign(vertices + 1, vector<int>(vertices + 1, 0));
    30. cin >> D;
    31. for (int i = 0; i < n; i++) {
    32. int x, y;
    33. cin >> x >> y;
    34. node.push_back(Node{ x,y });
    35. }
    36. node.push_back(Node{ 0,0 });
    37. for (int i = 0; i < n; i++) {
    38. for (int j = 0; j < n; j++) {
    39. if (i == j || distance(node[i], node[j]) > D) adjMatrix[i][j] = 0;
    40. else if (distance(node[i], node[j]) <= D) {
    41. adjMatrix[i][j] = 1;
    42. adjMatrix[j][i] = 1;
    43. }
    44. }
    45. }
    46. for (int i = 0; i < n; i++) {
    47. if (node[i].x*node[i].x + node[i].y * node[i].y <= (7.5 + D)*(7.5 + D)) {
    48. adjMatrix[n][i] = 1;
    49. }
    50. else {
    51. adjMatrix[n][i] = 0;
    52. }
    53. }
    54. adjMatrix[n][n] = 0;
    55. }
    56. double distance(Node a, Node b) {
    57. return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
    58. }
    59. void addEdge(int from, int to, int value) {
    60. adjMatrix[from][to] = value;
    61. }
    62. int check(Node p) {
    63. if (p.x - (-50) <= D || 50 - p.x <= D || p.y - (-50) <= D || 50 - p.y <= D) {
    64. return 1;
    65. }
    66. else return 0;
    67. }
    68. int DFS() {
    69. vis.assign(vertices, 0);
    70. flag = 0;
    71. for (int i = 0; i < vertices - 1; i++)
    72. {
    73. if (!vis[i] && adjMatrix[vertices - 1][i]) // 遍历图的起点只能从(0,0)开始
    74. {
    75. DFSRecursive(i);
    76. }
    77. if (flag == 1) return 1;
    78. }
    79. return 0;
    80. }
    81. void DFSRecursive(int vertex) {
    82. vis[vertex] = 1;
    83. if (check(node[vertex]) || flag == 1)
    84. {
    85. flag = 1; return;
    86. }
    87. for (int i = 0; i < vertices - 1; i++)
    88. {
    89. if (!vis[i] && adjMatrix[vertex][i])
    90. {
    91. DFSRecursive(i);
    92. }
    93. }
    94. }
    95. };
    96. int main() {
    97. Graph G;
    98. G.build_Graph();
    99. int check = G.DFS();
    100. if (check == 1) {
    101. printf("Yes\n");
    102. }
    103. else {
    104. printf("No\n");
    105. }
    106. }

    13、判断环

    无向图:将图中度为1的顶点一个个删掉,同时把与该顶点相连的顶点度数减1,若图中仍存在度大于1的顶点,说明图中有环。

    有向图:将图中入度为0的顶点一个个删掉,同时把与该顶点相连的顶点入度减1,若图中仍存在入读不为0的顶点,说明图中有环。

    1. // 无向图判断环
    2. #include
    3. #define MAXN 100010
    4. using namespace std;
    5. vectorint>> vec;
    6. int n;
    7. vector<int> d;
    8. int main()
    9. {
    10. cin >> n;
    11. d.resize(n + 1, 0);
    12. vec.resize(n + 1);
    13. for (int i = 1; i <= n; i++) {
    14. int a, b;
    15. cin >> a >> b;
    16. d[a]++, d[b]++;
    17. vec[a].push_back(b);
    18. vec[b].push_back(a);
    19. }
    20. queue<int> q;
    21. for (int i = 1; i <= n; i++) {
    22. if (d[i] == 1) q.push(i);
    23. }
    24. while (!q.empty()) {
    25. int p = q.front();
    26. q.pop();
    27. for (int i = 0; i < vec[p].size(); i++) {
    28. --d[vec[p][i]];
    29. if (d[vec[p][i]] == 1) {
    30. q.push(vec[p][i]);
    31. }
    32. }
    33. }
    34. for (int i = 1; i <= n; i++) {
    35. if (d[i] > 1) cout << i << " ";
    36. }
    37. return 0;
    38. }

  • 相关阅读:
    Linux:最全的开发常用命令
    python 多项式回归以及可视化
    流量封顶时代,容联七陌智能客服构筑企业“第二增长曲线”
    谷粒商城P85发布商品时规格参数不显示问题
    360 评估反馈工具 – 它的含义以及使用它的原因
    【BOOST C++ 17 出错处理】(3) Boost.Exception
    前端—— 分层模型和应用协议
    解决 MyBatis-Plus 中 ID 自增问题
    直播预告 | 10月12日虹科灭菌原理和灭菌工艺验证免费课程开讲,晚8点不见不散!
    1.0、C语言数据结构 ——初识数据结构和算法
  • 原文地址:https://blog.csdn.net/m0_74099951/article/details/134216177