拓扑排序精讲
一堆软件有前置依赖关系,找到一条可行的安装顺序
思路:
1.找到入度为0的节点;2.将入度为0的节点加入结果集,然后删除该节点。重复以上过程即可
细节:
入度用一个数组记录,记录每个节点的入度;
**如何删除节点?**只需把节点所连接的子节点的入度都减一;
如何找到节点所连接的所有子节点? 定义一个键值对,键是父节点,值是所连接的节点组成的数组;
**如何找到入度为0的节点?**不需要每次都遍历,只需要在遇到入度为0的节点时就加入队列,然后只要队列不空,就循环执行"将队头取出,加入结果集,删除队头,删除节点,再判断节点连接的子节点是否入度为0,如果是就也加入"。
cpp
#include<iostream>
using namespace std;
#include<vector>
#include<queue>
#include<unordered_map>
int main(){
int n,m,s,t;
cin>>n>>m;
vector<int> indegree(n,0);
vector<int> result;
unordered_map<int,vector<int>> umap;
queue<int> que;
while(m--){
cin>>s>>t;
indegree[t]++;
umap[s].push_back(t);
}
for(int i=0;i<n;i++){
if(indegree[i]==0){
que.push(i);
}
}
while(!que.empty()){
int cur = que.front(); que.pop();
result.push_back(cur);
vector<int> notes = umap[cur];
if(notes.size()){
for(int i=0;i<notes.size();i++){
indegree[notes[i]]--;
if(indegree[notes[i]]==0) que.push(notes[i]);
}
}
}
if(n == result.size()){
for(int i=0;i<n-1;i++){
cout<<result[i]<<" ";
}
cout<<result[n-1]<<endl;
}else{
cout<<-1<<endl;
}
}
dijkstra(朴素版)精讲
本题是在有向有权图中,找到起点到终点的最短路径距离
思路:和prim算法高度类似
1.找到距离起点最近的没被访问过的节点(搜索minDist中的没被访问过的节点的最小值)
2.将该节点标记为访问过(将visitedcur置为true)
3.更新所有没被访问过的节点到起点的最短距离(遍历节点,判断节点是否访问过 && 是否和当前节点连接 && 是否到起点的距离小于之前记录的距离(因为如果途径新的当前节点可能会获得更短的距离))
cpp
#include<iostream>
#include<vector>
#include <climits>
using namespace std;
int main(){
int n,m,s,t,val;
cin>>n>>m;
vector<vector<int>> graph(n+1,vector<int>(n+1,INT_MAX));
while(m--){
cin>>s>>t>>val;
graph[s][t]= val;
}
vector<int> minDist(n+1, INT_MAX);
vector<bool> visited(n+1, false);
int start = 1;
int end = n;
minDist[1] = 0;
for(int i=1;i<=n;i++){
int cur = 1;
int minval = INT_MAX;
for(int j=1;j<=n;j++){
if(visited[j]==false && minval>minDist[j]){
minval = minDist[j];
cur = j;
}
}
visited[cur] = true;
for(int k=1;k<=n;k++){
if(visited[k] == false &&graph[cur][k]!=INT_MAX && graph[cur][k]+minDist[cur]<minDist[k]){
minDist[k] = graph[cur][k]+minDist[cur];
}
}
}
if(minDist[n]==INT_MAX){
cout<<-1<<endl;
return 0;
}
cout<<minDist[n]<<endl;
}