• 图论入门题题解


    ✨欢迎来到脑子不好的小菜鸟的文章✨

          🎈创作不易,麻烦点点赞哦🎈

              所属专栏:刷题_脑子不好的小菜鸟的博客-CSDN博客

              我的主页:脑子不好的小菜鸟

              文章特点:关键点和步骤讲解放在

              代码相应位置

    拓扑排序 / 家谱树
    https://vjudge.net/contest/613618#problem/A

    1. //拓扑排序:找到入度为0的点,将其写入答案,再删去其箭头,再继续找入度为0的点,循环往复
    2. vector<int>edeg[101];
    3. int n, deg[101] = { 0 };//入度
    4. void init()//建图
    5. {
    6. cin >> n;
    7. int i, val;
    8. for (i = 1; i <= n; i++)
    9. {
    10. while (cin >> val && val != 0)
    11. {
    12. edeg[i].push_back(val);
    13. deg[val]++;
    14. }
    15. }
    16. }
    17. void toposort()//拓扑排序
    18. {
    19. int i;
    20. queue<int> que;
    21. for (i = 1; i <= n; i++)
    22. {
    23. if (deg[i] == 0)
    24. {
    25. cout << i << ' ';
    26. que.push(i);
    27. }
    28. }
    29. while (!que.empty())
    30. {
    31. int t = que.front();
    32. que.pop();
    33. for (int i : edeg[t])
    34. //相当于i表示edeg[t]的第一个元素,进行一次循环后就是第二个元素,循环往复
    35. {
    36. deg[i]--;
    37. if (deg[i] == 0)
    38. {
    39. cout << i << ' ';
    40. que.push(i);
    41. //push的原因:可能i(也就是edeg[t])还有箭头指向其他的数,也就是后面辈分比它小的,要通过i来找比它辈分小的
    42. }
    43. }
    44. }
    45. }
    46. int main()
    47. {
    48. init();//建图
    49. toposort();//拓扑排序
    50. return 0;
    51. }

    P3371 【模板】单源最短路径(弱化版)
    https://www.luogu.com.cn/problem/P3371

    1. ///*法一:邻接矩阵*/
    2. 占的空间较多,时间复杂度较大,不适合
    3. /*法二:结构体,堆优化*/
    4. //要一个结构体,存一个点相关的东西(to, wei, next)(终点, 权值, 下一个儿子)
    5. //cnt:结构体下标
    6. //head[MAX]:head[i]:查找i点的第一个儿子
    7. //pos:将被标记的值
    8. //ans[MAX]:最短距离
    9. //visit[MAX]:是否被标记过
    10. //题解:https://www.luogu.com.cn/article/oswxjzrl
    11. #include #include
    12. using namespace std;
    13. const int MAX = 1e6;int cnt;//结构体下标int visit[MAX];//标记int n, m, s;int head[MAX];//存放儿子int ans[MAX];//放到起点的最短距离
    14. struct EDGE
    15. {
    16. int wei;//权值
    17. int to;//目的地
    18. int next;//下一个儿子
    19. }edge[MAX];
    20. void add(int u, int v, int w){
    21. cnt++;
    22. edge[cnt].wei = w;
    23. edge[cnt].to = v;
    24. edge[cnt].next = head[u];//将下一个儿子记录
    25. head[u] = cnt;//更新第一个儿子
    26. }
    27. int main(){
    28. cin >> n >> m >> s;
    29. int i;
    30. //初始化ans
    31. for (i = 1; i <= n; i++)
    32. ans[i] = INT_MAX;
    33. ans[s] = 0;
    34. int u, v, w;
    35. for (i = 1; i <= m; i++)
    36. {
    37. cin >> u >> v >> w;
    38. add(u, v, w);
    39. }
    40. int pos = s;//初始化pos为s
    41. while (visit[pos] == 0)
    42. {
    43. int minn = INT_MAX;//注意更新
    44. visit[pos] = 1;//标记
    45. //更新儿子的最短路径
    46. for (i = head[pos]; i != 0; i = edge[i].next)
    47. {
    48. if (visit[edge[i].to] == 0 && ans[edge[i].to] > ans[pos] + edge[i].wei)
    49. ans[edge[i].to] = ans[pos] + edge[i].wei;
    50. }
    51. //找最短路径
    52. for (i = 1; i <= n; i++)
    53. {
    54. if (visit[i] == 0 && ans[i] < minn)
    55. {
    56. minn = ans[i];
    57. pos = i;
    58. }
    59. }
    60. }
    61. for (i = 1; i <= n; i++)
    62. cout << ans[i] << ' ';
    63. cout << endl;
    64. return 0;
    65. }

    P4779 【模板】单源最短路径(标准版)
    https://www.luogu.com.cn/problem/P4779

    注意:该题用上一题的代码会超时,因此要用堆优化,也就是优先队列

    1. //友情提示:正权图 请 使用dijkstra算法, 负权图 请 使用SPFA算法
    2. //弱化版的代码超时---->要用堆优化
    3. /*
    4. 核心:priority_queue< pair > 用优先队列来取最近的点,就不用遍历找点了
    5. 在pq中,是按pair的第一个元素(first)由大到小排序的,所以pair<距离,点号>,注意因为要的是最小值,所以距离要存负值
    6. 其实距离是纯纯的工具人,我们只是需要它来维持点的排序
    7. 每次取队首h,取出的就是dis最短的点
    8. 还要注意:
    9. 如果这个点的dis不等于h的dis,说明这个点在入队之后被更新了,那么我们就不用这个点了,直接continue;
    10. 因为后面会有个h2点比h1的dis更小,用h1更新就没有意义了
    11. */
    12. //使用优先队列,注意:优先队列是从大到小排列,所以存进去应该存负数
    13. C代码:
    14. #include
    15. /*堆优化:利用优先队列,降低复杂度,直接排序,注意优先队列是由大到小排列的,因此距离是负数 */
    16. #include
    17. #include
    18. using namespace std;
    19. const int MAX = 1e6;
    20. int n, m, s;
    21. int ans[MAX];
    22. int cnt;
    23. int head[MAX];
    24. int visit[MAX];
    25. struct EDGE
    26. {
    27. int to;
    28. int next;
    29. int wei;
    30. }edge[MAX];
    31. void add(int u, int v, int w)
    32. {
    33. cnt++;
    34. edge[cnt].wei = w;
    35. edge[cnt].to = v;
    36. edge[cnt].next = head[u];
    37. head[u] = cnt;
    38. }
    39. int main()
    40. {
    41. int i;
    42. int u, v, w;
    43. cin >> n >> m >> s;
    44. for (i = 1; i <= n; i++)
    45. ans[i] = INT_MAX;
    46. ans[s] = 0;
    47. for (i = 1; i <= m; i++)
    48. {
    49. cin >> u >> v >> w;
    50. add(u, v, w);
    51. }
    52. priority_queueint, int> >que;//距离,点
    53. que.push({0, s});
    54. while (!que.empty())
    55. {
    56. int qh = que.top().first;
    57. int h = que.top().second;
    58. que.pop();/*记得pop()!!!!!!!!!*/
    59. if (visit[h] == 0)
    60. {
    61. visit[h] = 1;
    62. for (i = head[h]; i != 0; i = edge[i].next)//不断找下一个儿子,直到找完
    63. {
    64. if (ans[edge[i].to] > ans[h] + edge[i].wei)
    65. {
    66. ans[edge[i].to] = ans[h] + edge[i].wei;
    67. if (visit[edge[i].to] == 0)
    68. que.push({ -ans[edge[i].to], edge[i].to });
    69. }
    70. }
    71. }
    72. }
    73. for (i = 1; i <= n; i++)
    74. cout << ans[i] << ' ';
    75. cout << endl;
    76. return 0;
    77. }

    B3647 【模板】Floyd
    https://www.luogu.com.cn/problem/B3647 

    1. //floyd算法
    2. //要注意中转点,可以直接i到j,也可以i->k,k->j,因此要比较两个数据的大小,最后表中的是最短路径
    3. //注意是无向图
    4. #include
    5. int main()
    6. {
    7. int n, m, i, j, u, v, w;
    8. long long board[105][105] = { 0 };//存最短路径
    9. cin >> n >> m;
    10. for (i = 1; i <= n; i++)
    11. {
    12. for (j = 1; j <= n; j++)
    13. {
    14. if (i == j)
    15. board[i][j] = 0;
    16. else
    17. board[i][j] = INT_MAX;
    18. }
    19. }
    20. for (i = 1; i <= m; i++)
    21. {
    22. cin >> u >> v >> w;
    23. if (w < board[u][v])
    24. board[u][v] = w;
    25. if (w < board[v][u])
    26. board[v][u] = w;
    27. }
    28. int k;
    29. for (k = 1; k <= n; k++)//把k当中转点,注意是放在i,j循环的外面
    30. {
    31. for (i = 1; i <= n; i++)//行,列
    32. {
    33. if (i == k)
    34. continue;
    35. for (j = 1; j <= n; j++)
    36. {
    37. if (j == k)
    38. continue;
    39. if (i == j)
    40. continue;
    41. if (board[i][k] != INT_MAX && board[k][j] != INT_MAX)
    42. board[i][j] = min(board[i][j], board[i][k] + board[k][j]);
    43. }
    44. }
    45. }
    46. for (i = 1; i <= n; i++)
    47. {
    48. for (j = 1; j <= n; j++)
    49. {
    50. cout << board[i][j] << ' ';
    51. }
    52. cout << endl;
    53. }
    54. return 0;
    55. }

    恭喜你啦,今天又进步了一点点~

  • 相关阅读:
    如何在电脑和手机设备上编辑只读 PDF
    商业智能BI为什么能在数字化时代成为企业的基础建设
    Spring—Bean的装配方式—基于注解的七种装配方式
    理解MySQL事务
    JavaWeb-解析Http协议
    利用hutool导出Excel
    Maya获取材质ShadingEngine信息
    985硕的4家大厂实习与校招经历专题分享(part1)
    【程序的编译和预处理】
    总结篇:二叉树遍历
  • 原文地址:https://blog.csdn.net/2301_79293429/article/details/136565883