📜  门|门 CS 1999 |第 43 题(1)

📅  最后修改于: 2023-12-03 15:12:46.098000             🧑  作者: Mango

题目介绍

本题为门 | 门 CS 1999第43题,属于数据结构与算法分类,难度为中等。

题目描述

有一个 $n$ 个点 $m$ 条边的有向图,边权均为正整数。定义点 $i$ 的度数为该点的入度与出度之和,求度数最小的点,若有多个,输出点标号最小的那个。

输入格式
  • 第一行包含两个整数 $n$ 和 $m$,表示图中点和边的数量。
  • 接下来 $m$ 行,每行包含三个整数 $x_i$, $y_i$ 和 $z_i$,表示存在一条从 $x_i$ 到 $y_i$ 权值为 $z_i$ 的有向边。
输出格式
  • 输出最小度数的点的标号,如果有多个,输出点标号最小的那个。
输入样例
4 5
1 2 2
1 3 5
2 3 1
3 1 2
3 4 5
输出样例
3

题目思路

本题需要求解的是度数最小的点,因此我们需要统计每个点的度数,并求出最小的度数。

不难想到,对于每个点,我们可以分别计算它的入度和出度,最后将两者之和求出即可得到该点的度数。

统计出度简单,只需使用邻接表存储图,遍历每个节点的出边即可。统计入度相对比较麻烦,需要对每个节点的所有出边进行遍历,找出对应的终点节点,并统计其入度。

在求完每个点的度数后,只需遍历所有点并找出最小度数即可,注意输出标号最小的那个。

代码实现

实现上述思路,我们可以先定义一个用于存储邻接表的结构体,并封装辅助函数来进行入度和度数的计算。最终算法的伪代码如下:

struct Node {
    int v, w;
    Node *next;
};

// 存储邻接表的结构体
struct Graph {
    int n, m;
    Node *heads;    // 存储每个节点的邻接表头
};

// 辅助函数:计算指定节点的出度
int out_deg(Graph &g, int v) {
    int ans = 0;
    for (Node *p = g.heads[v].next; p != nullptr; p = p->next)
        ans++;
    return ans;
}

// 辅助函数:计算指定节点的入度
int in_deg(Graph &g, int v) {
    int ans = 0;
    for (int u = 1; u <= g.n; u++) {
        for (Node *p = g.heads[u].next; p != nullptr; p = p->next) {
            if (p->v == v) {
                ans++;
                break;
            }
        }
    }
    return ans;
}

// 主函数
int main() {
    Graph g;
    // 读入图,初始化邻接表等
    for (int i = 1; i <= g.n; i++) {
        int d = in_deg(g, i) + out_deg(g, i);
        if (d < min_deg) {
            ans = i;
            min_deg = d;
        } else if (d == min_deg && i < ans) {
            ans = i;
        }
    }
    // 输出结果
    printf("%d", ans);
    return 0;
}

算法的时间复杂度为 $O(n^3)$,虽然在本题数据范围下可以通过,但仍有优化的空间。例如,我们可以使用邻接表和邻接矩阵结合的方式来进行入度的统计,从而将时间复杂度降为 $O(n^2)$。此外,我们也可以使用拓扑排序(BFS)来统计度数,进一步将时间复杂度降为 $O(n+m)$。

拓展思考

  1. 本题还可以进一步扩展,如果要求度数最小的点中,离指定点最近的点应该怎么做?

答:我们可以先使用 BFS 遍历指定点所在的连通块,并记录每个点到指定点的距离。然后再遍历整张图,只考虑合法的点,即和指定点同处一个连通块的点,统计这些点的度数。在统计完度数之后,遍历所有度数最小的点,找到其中离指定点最近的点即可。

  1. 本题用 C++ 实现的话,如何避免手动删除邻接表中的节点所带来的麻烦?

答:我们可以使用 C++11 的智能指针技术,将邻接表中的节点存储为 std::unique_ptr<Node> 类型,从而避免了手动释放内存的麻烦。

总结

本题主要考察对于有向图的建模及基础算法的掌握,例如邻接表的使用、度数的计算等。对于初学者而言,建议先学习邻接表、BFS 等基础算法,再考虑更高级的优化和扩展。在实际编码时,还需要注意细节,例如输出最小度数的那个节点时,需要按照题目要求返回标号最小的那个。