【算法入门&图论】【模板】拓扑排序 【模板】单源最短路2 最小生成树_ab15 【模板(1)

            que.push(v);
    }
    cnt++;
}
// 若计数器与顶点数相同则图无环,存在拓扑排序
if (cnt == n) {
    for (int i = 0; i < res.size(); i++) {
        cout << res[i];
        // 限制输出空格的条件
        if (i != res.size() - 1) {
            cout << " ";
        }
    }
} else {
    cout << -1;
}
return 0;

}


*重要注释:*


* `adjList`数组是`vector`类型的,用来模拟邻接表
	+ 使用每个元素为一个数组的`vector`容器模拟邻接表进行建图
	+ `vector[a]`所对应的数组中存储着该顶点所指向的其他顶点
	+ `inDegree`数组代表每一个顶点的入度情况
* 使用一个队列,初始时将所有入度为0的顶点全部入队,之后采用`BFS`的思想:
	+ 依次取出队头元素并存入结果数组中,然后在邻接表中遍历该队头元素所指向的其他顶点
	+ 将这些顶点的入度全部减一,若减一后某顶点的入度变为0,则将该顶点进行入队操作,  
	 重复此步骤直至队列为空为止。
* 设置一个用于判断图中是否存在环(**是否可以得到拓扑序列**)的计数器,在弹出队头元素后要将计数器加一,最后队列为空后,若计数器的值与顶点数相同,则说明图不存在环,可以得到拓扑序列。




---


## 2、AB14 最小生成树



> 
> 题目链接:[最小生成树](https://bbs.csdn.net/topics/618545628)
> 
> 
> 


![在这里插入图片描述](https://img-blog.csdnimg.cn/ef33f317f7c543bcb4e23a6d067afb09.png)


### 2.1、解题思路


本题要求在最小花费下将 n 户人家连接起来,很显然是最小生成树的问题,我采用`prim`算法:


1. 将二维数组`cost`按权升序排序,那么`cost[0][2]`就是最小的一个权值
2. 将连接这条边的两个顶点放入`unordered_set`容器:
	* `unordered_set` 容器的元素是无序的,可以用来给顶点去重
	* 内置的 `find` 方法也很好用
3. 接下来遍历`cost`二维数组,直到所有顶点全部放入容器中,遍历结束
4. 将遍历中权值的和返回,程序结束


### 2.2、代码实现与注释


*本题源码:*



class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
* 返回最小的花费代价使得这n户人家连接起来
* @param n int n户人家的村庄
* @param m int m条路
* @param cost intvector<vector<>> 一维3个参数,表示连接1个村庄到另外1个村庄的花费的代价
* @return int
*/

// 自定义排序规则:按权递增
static bool cmp(vector<int>& x, vector<int>& y) {
    return x[2] < y[2];
}
int miniSpanningTree(int n, int m, vector<vector<int> >& cost) {
    unordered_set<int> points; // 记录不重复的点
    int res = 0;
    sort(cost.begin(), cost.end(), cmp);
    res += cost[0][2]; // 此时res 为最小权值
    // 将最小边加入
    points.insert(cost[0][0]);
    points.insert(cost[0][1]);
    while (1) {
        if (points.size() == n)
            break; // 所有的点连同后退出循环
        // 遍历剩余的边
        for (auto it = cost.begin(); it != cost.end(); it++) {
            // 如果边仅有一个点在集合内就加入
            if ((points.find((\*it)[0]) != points.end() &&
                points.find((\*it)[1]) == points.end()) ||
                (points.find((\*it)[1]) != points.end() &&
                points.find((\*it)[0]) == points.end()))
                {
                    res += (\*it)[2];
                    points.insert((\*it)[0]);
                    points.insert((\*it)[1]);
                    cost.erase(it); // 删除该边
                    break;
                }
        }
    }
    return res;
}

};


*重要注释:*


* `cmp` 是自定义的一个按权递增的排序函数,配合`sort`函数来将`cost`排序
	+ 相关知识点可以参考我的博文:[自定义排序规则](https://bbs.csdn.net/topics/618545628)
* `auto`关键字可以自动推导表达式类型,在这里就相当于`vector<vector<int>>::iterator`
* `if`的条件很长,但其实就是将有且仅有一个顶点在`points`中的边找到:
	+ 获取该边的权值并求和,将另一顶点插入到`points` 中
	+ 将该边删除,重新遍历`cost`,直到全部顶点被插入到`points`中
* 最终的 `res` 就是该题的结果,即最小花费。


## 3、AB15 单源最短路2



> 
> 题目链接:[单源最短路2](https://bbs.csdn.net/topics/618545628)
> 
> 
> 


![在这里插入图片描述](https://img-blog.csdnimg.cn/ede6f5ee8eb94be0a6e7ba5a9afccef9.png)![在这里插入图片描述](https://img-blog.csdnimg.cn/9794408295f4486f98c87be1c595da6b.png)


### 3.1、解题思路


使用`Dijkstra`算法(即不断从未处理集合中找当前距离源点最近的顶点以添加到已处理集合中,直至未处理集合为空的算法思想)


1. 对于无向图,采用邻接矩阵表示点与点的连接关系以及距离
2. 使用数组`dist`记录每个顶点与源点的距离:
	* 本题中就是记录顶点1与其他顶点的距离
3. 用一个布尔类型的数组记录顶点的处理情况:
	* 初始状态全部设为`false`,一经处理就设为`true`
4. 最终`dist[n]`就是顶点`n`到源点的最短距离


### 3.2、代码实现与注释


*本题源码*



#include
#include // 使用INT_MAX所需要引入的头文件
using namespace std;
const int N = 5000; // 注意题干,图的点数是固定值5000

int main() {

int G[N + 1][N + 1]; // 用于模拟邻接矩阵进行建图
for (int i = 1; i <= N; i++) {
    for (int j = 1; j <= N; j++) {
        G[i][j] = INT_MAX; // 先将邻接矩阵全部初始化为无穷大
    }
}
int n, m;
cin >> n >> m;
int u, v, w;
for (int i = 1; i <= m; i++) {
    cin >> u >> v >> w;
    G[u][v] = w;
    G[v][u] = w; // 需要关于主对角线对称,因此两边都需要存储
}
int dist[N + 1]; // 用于存储每个顶点当前与源点的最短距离

bool flag[N + 1]; // 用于记录每个顶点是否已经完成与源点最短距离的计算处理

for (int i = 1; i <= N; i++) {
    dist[i] = G[1][i]; // 初始设置为邻接矩阵中源点所在 行 的权值
    flag[i] = false;
}

dist[1] = 0;
flag[1] = true; // 将源点加入已处理集合

for (int i = 2; i <= N; i++) {
    int tmp = INT_MAX, index = 1;
    for (int j = 1; j <= N; j++) { // 遍历寻找与源点的最短距离
        if (flag[j] == false && dist[j] < tmp) {
            tmp = dist[j];
            index = j;
        }
    }
    if (index != 1) {
        flag[index] = true; // 找到后将其加入已处理集合
    }
    for (int j = 2; j <= N; j++) {
        if (flag[j] == false && G[index][j] != INT_MAX) {
            if (G[index][j] + dist[index] < dist[j]) {
                dist[j] = G[index][j] + dist[index]; // 更新最短路径
            }
        }
    }
}
if (dist[n] != INT_MAX) {
    cout << dist[n];
} else {
    cout << -1;
}
return 0;

}


*重要注释:*


![img](https://img-blog.csdnimg.cn/img_convert/8c02cf6294c4dd5b94a8e73afcfc1b9a.png)
![img](https://img-blog.csdnimg.cn/img_convert/c013007963f8f305d5a7449647e62002.png)
![img](https://img-blog.csdnimg.cn/img_convert/f71ad9f7d16b80d9e85b1784c67d6ddf.png)

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!**

**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**

**[需要这份系统化资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618545628)**

中...(img-X6gexH8p-1714738828790)]

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!**

**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**

**[需要这份系统化资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618545628)**

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值