C++图学习整理 最小生成树 在无向图中生成一棵树(n-1条边,无环,连通所有点),且这棵树的劝和最小
普利姆算法(Prim)——加点法
任选一点开始,找到离这个点最近的点,加入最小生成树
再继续去找离这个最小生成树最近的点,加入最小生成树中,重复步骤2
克鲁斯卡尔算法(Kruskal) ——加边法
找到最短边,判断其两个端点在不在一个连通分量里
若在,则跳过;若不在,加入最小生成树
洛谷例题 题目描述 如题,给出一个无向图,求出最小生成树,如果该图不连通,则输出 orz
。
输入格式 第一行包含两个整数 $N,M$,表示该图共有 $N$ 个结点和 $M$ 条无向边。
接下来 $M$ 行每行包含三个整数 $X_i,Y_i,Z_i$,表示有一条长度为 $Z_i$ 的无向边连接结点 $X_i,Y_i$。
输出格式 如果该图连通,则输出一个整数表示最小生成树的各边的长度之和。如果该图不连通则输出 orz
。
样例 #1 样例输入 #1 1 2 3 4 5 6 4 5 1 2 2 1 3 2 1 4 3 2 3 4 3 4 3
样例输出 #1
提示 数据规模:
对于 $20%$ 的数据,$N\le 5$,$M\le 20$。
对于 $40%$ 的数据,$N\le 50$,$M\le 2500$。
对于 $70%$ 的数据,$N\le 500$,$M\le 10^4$。
对于 $100%$ 的数据:$1\le N\le 5000$,$1\le M\le 2\times 10^5$,$1\le Z_i \le 10^4$。
样例解释:
所以最小生成树的总边权为 $2+2+3=7$。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 #include <cstdio> #include <queue> #define INF 2147483647 #define MAXN 5001 #define MAXM 200001 using namespace std;int head[MAXN], dis[MAXN]; bool vis[MAXN]; int edge_sum = 0 ; int n, m, MST; struct Edge { int next, to, dis; } edge[MAXM << 1 ]; void addedge (int from, int to, int dis) { edge[++edge_sum].next = head[from]; edge[edge_sum].to = to; edge[edge_sum].dis = dis; head[from] = edge_sum; } struct node { int u, dis; bool operator <(const node& rhs) const { return dis > rhs.dis; } }; void prim () { priority_queue<node> q; for (register int i = 0 ; i <= n; i++) dis[i] = INF; dis[1 ] = 0 ; q.push ((node{1 , 0 })); while (!q.empty ()) { node tmp = q.top (); q.pop (); int u = tmp.u, d = tmp.dis; if (vis[u]) continue ; vis[u] = 1 ; for (register int j = head[u]; j; j = edge[j].next) { if (!vis[edge[j].to] && edge[j].dis < dis[edge[j].to]) { dis[edge[j].to] = edge[j].dis; if (!vis[edge[j].to]) q.push ((node){edge[j].to, dis[edge[j].to]}); } } } } int main () { scanf ("%d%d" , &n, &m); for (register int i = 1 ; i <= m; i++) { int x, y, z; scanf ("%d%d%d" , &x, &y, &z); addedge (x, y, z); addedge (y, x, z); } prim (); bool flag = 0 ; for (register int i = 1 ; i <= n; i++) { if (dis[i] == INF) flag = 1 ; MST += dis[i]; } if (!flag) printf ("%d\n" , MST); else printf ("orz\n" ); return 0 ; }
最短路径 迪杰斯特拉(Dijkstra)算法——找到a到其他点的最短路径 每次都选距离a最近的点,然后更新
弗洛伊德(Floyd)算法 求任意两个点的最短路径,使用邻接矩阵来存储
数组D保存任意两个点的最短路径
数组Path保存任意两个点之间的最短路径本身
关键路径——AOE网中最长的路 AOE —边上有权值的图
拓扑排序 —每次选入度为0的点,然后删除这个点和它的出边
思路 AOE网中的节点为事件,边为路径
v—vertex(事件);e—early;l—late
先设变量ve,vl,e,l
通过一次拓扑排序,求出每个节点的ve;
再通过一次逆拓扑排序,求出每个节点的vl;