📜  图论-有用的资源(1)

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

图论-有用的资源

1. 什么是图论?

图论是数学的一个分支,研究的是图和网络的有关性质和算法。图是由一些点和连接它们的线(边)组成的。图论主题包括:图的嵌入、图的着色、图的最大独立集、图的最优化、特殊类型的图、网络流等。

2. 有用的资源
2.1 学习资料
2.2 常用算法

2.2.1 最短路径算法

  • Dijkstra算法:用于计算某个源点到其他点的最短路径。
// Dijkstra算法示例代码
const int MAXV = 1001;
const int INF = INT_MAX; // 无穷大
int n; // 图的节点总数
int graph[MAXV][MAXV]; // 图的邻接矩阵
int d[MAXV]; // 保存到各个节点的最短距离
bool used[MAXV]; // 是否已经计算出了最短距离

void dijkstra(int s) {
    fill(d, d + MAXV, INF); // 初始化距离
    fill(used, used + MAXV, false);

    d[s] = 0; // 源点到源点的距离为0
    
    while (true) {
        int v = -1;
        for (int u = 0; u < n; u++) {
            if (!used[u] && (v == -1 || d[u] < d[v])) v = u;
        }
        if (v == -1) break;
        used[v] = true;

        for (int u = 0; u < n; u++) {
            d[u] = min(d[u], d[v] + graph[v][u]);
        }
    }
}

  • Bellman-Ford算法:计算带有边权(可能为负数)的图中单源最短路径。
// Bellman-Ford算法示例代码
struct edge { int from, to, cost; };
edge es[MAXE];
int d[MAXV]; // 保存到各个节点的最短距离
int V, E;

void bellman_ford(int s) {
    for (int i = 0; i < V; i++)
        d[i] = INF;
    d[s] = 0;

    while (true) {
        bool update = false;
        for (int i = 0; i < E; i++) {
            edge e = es[i];
            if (d[e.from] != INF && d[e.to] > d[e.from] + e.cost) {
                d[e.to] = d[e.from] + e.cost;
                update = true;
            }
        }
        if (!update) break;
    }
}

2.2.2 最小生成树

  • Prim算法:求无向带权连通图的最小生成树。
// Prim算法示例代码
const int MAXV = 1001;
const int INF = INT_MAX;
int n;
int graph[MAXV][MAXV]; // 图的邻接矩阵
int d[MAXV]; // 记录到树中每个节点的距离
bool used[MAXV]; // 已经加入树中的点
int prim() {
    fill(d, d + MAXV, INF);
    fill(used, used + MAXV, false);
    d[0] = 0; // 从0号节点开始

    int res = 0; // 最小生成树的边权和
    while (true) {
        int v = -1;
        // 选择距离树最近的边
        for (int u = 0; u < n; u++) {
            if (!used[u] && (v == -1 || d[u] < d[v])) v = u;
        }
        if (v == -1) break;

        used[v] = true;
        res += d[v];

        // 更新到树中每个节点的距离
        for (int u = 0; u < n; u++) {
            d[u] = min(d[u], graph[v][u]);
        }
    }
    return res;
}
  • Kruskal算法:求带权连通图的最小生成树。
// Kruskal算法示例代码
struct edge { int u, v, cost; };
edge es[MAXE];
int V, E;
int uf[MAXV];

bool cmp(const edge& a, const edge& b) {
    return a.cost < b.cost;
}

int kruskal() {
    sort(es, es + E, cmp);
    init_union_find(V);

    int res = 0;
    for (int i = 0; i < E; i++) {
        edge e = es[i];
        if (!same(e.u, e.v)) {
            unite(e.u, e.v);
            res += e.cost;
        }
    }
    return res;
}

3. 总结

图论是算法中一道非常重要的题目,通过学习和掌握常用的算法,可以大大提升程序员的算法竞赛水平。同时,熟悉常用工具和资源,也能使工作和学习更加便捷。

参考资料: