代码随想录打卡Day63

今天学拓扑排序,和dijkstra算法,拓扑排序的思路第一次见,dijkstra算法的题目看起来和昨天写的prim算法很像,但是还是有细微的区别。感觉两个题目看完题解以后也没有那么难实现。

117. 软件构建(卡码网)

这道题用拓扑排序,核心思路很简单,就是不断找入度为0的节点,入度为0的节点就是图的起点,将入度为0的节点找到后,将其放入一个队列中(因为可能会有多个入度为0的节点)然后不断读取队头元素并弹出,读取到了队头元素,再访问依赖于队头元素的其他元素(必须要先安装队头文件才能安装的那些文件),将它们对应的入度-1,如果又有文件的入度被减一后变成0,则将对应的文件也加入队列,只要队列不为空,这个循环就将一直进行下去。

#include<iostream>
#include<vector>
#include<queue>
#include<unordered_map>

using namespace std;

int main(){
    int N, M;
    cin >> N >> M;  //N个文件,M条依赖关系(边)
    vector<int> inDegree(N, 0);  //统计各个节点的入度
    unordered_map<int, vector<int>> My_Map;   //统计文件依赖关系
    for(int i = 0; i < M; i++){
        int s, t;
        cin >> s >> t;  // s -> t
        inDegree[t]++;
        My_Map[s].push_back(t);   //记录s指向哪些文件
    }
    //开始BFS
    queue<int> My_Queue;
    vector<int> result;
    for(int i = 0; i < N; i++){
        if(inDegree[i] == 0)  //将入度为0的节点压入队列中
            My_Queue.push(i);
    }
    while(!My_Queue.empty()){
        int current = My_Queue.front();
        My_Queue.pop();
        result.push_back(current);
        vector<int> files = My_Map[current];  //获取current指向的文件
        if(files.size() > 0){  //存在依赖文件
            for(int i = 0; i < files.size(); i++){
                inDegree[files[i]]--;
                if(inDegree[files[i]] == 0)  //出现了新的起点,需要入队
                    My_Queue.push(files[i]);
            }
        }
    }
    if(result.size() < N) cout << -1 << endl;
    else{
        for(int i = 0; i < N; i++){
            if(i < N - 1) cout << result[i] << " ";
            else cout << result[i] << endl;
        }
    }
    return 0;
}

47. 参加科学大会(卡码网)

这道题和昨天prim算法那道题很像,但是二者有一些区别,昨天寻宝的题目是必须将所有的节点都加入最小生成树中,而本题不一定要将所有节点都加入路径中,因为并不是所有节点都可以到达;其次,两道题构造的minDist数组意义不一样,寻宝中的minDist数组的含义是:编号为i的节点与最小生成树之间的最小距离为minDist[i],minDist[i]可能是i号节点与生成树中任意一个节点的距离,取最小值即可,而本题中minDist数组的含义是:编号为i的节点与起始站点的最小距离为minDist[i],二者在定义上也有区别;最后,在更新minDist数组的时候,判定条件也不同,寻宝的判定条件是:当前遍历到的节点不在最小生成树中,且当前节点在current节点加入后与最小生成数的距离小于在current节点加入之前与最小生成树之间的距离,此时才更新minDist数组;而本题更新minDist数组的条件为:当前遍历到的节点不在路径中,且current可以到达当前节点,且当前节点与起点之间的距离(从current节点到当前节点的距离+起点到current节点的距离) < current节点加入路线之前当前节点与起点之间的距离。
除此以外,其他地方都大同小异的。在循环结束后直接判断minDist[end]是不是INT_MAX,如果是的话说明无法到达终点站,直接打印-1,否则打印minDist[end]。

#include<iostream>
#include<vector>
#include <climits>

using namespace std;

int main(){
    int N, M;
    cin >> N >> M;  //N个车站(节点),M条路(边)
    vector<vector<int>> grid(N + 1, vector<int> (N + 1, INT_MAX));    //记录整个公交线路图
    for(int i = 0; i < M; i++){
        int S, E, V;
        cin >> S >> E >> V;  // S -> E  花费V单位的时间
        grid[S][E] = V;
    }
    vector<bool> visited(N + 1, false);  //记录各个公交站点是否已经被访问
    vector<int> minDist(N + 1, INT_MAX);   //记录各个节点到出发点的最短距离
    int start = 1;   //起始站点
    int end = N;     //终点站
    minDist[start] = 0;
    for(int i = 1; i <= N; i++){  //至多循环N次,添加N个节点
        //第一步,选源点到哪个节点近且该节点未被访问过
        int current = 0;  //当前节点
        int minVal = INT_MAX;   
        for(int j = 1; j <= N; j++){
            if(!visited[j] && minDist[j] < minVal){
                current = j;
                minVal = minDist[j];
            }
        }
        //第二步,该最近节点被标记访问过
        visited[current] = true;
        //第三步,更新非访问节点到源点的距离(即更新minDist数组)
        for(int j = 1; j <= N; j++){
            //更新条件:
            //1. 当前节点未被访问
            //2. 从current节点可以到达当前节点
            //3. 当前节点与起点之间的距离(从current节点到当前节点的距离+起点到current节点的距离)
            //    < current节点加入路线之前当前节点与起点之间的距离
            if(!visited[j] && grid[current][j] != INT_MAX 
            && minDist[j] > minVal + grid[current][j])
                minDist[j] = minVal + grid[current][j];
        }
    }
    if(minDist[end] == INT_MAX) cout << -1 << endl;
    else cout << minDist[end] << endl;
    return 0;
}

还剩下三天的训练任务!!加油!!曙光不远了!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值