Dijkstra算法用于求解一个点到所有点的距离
例子
5 5 1(5个点 5条边 起点为1号节点)
1 2 20(下面5行是5条边的起点、终点与权值)
2 3 30
3 4 20
4 5 20
1 5 100
代码
//原版Dijkstra #include<iostream> #include<algorithm> #include<cstdio> #include<cmath> using namespace std; int edges[10002][10002]; int dist[10002]; int visited[10002]; #define inf 0x3f3f3f3f int n, m, s; void Dijkstra() { fill(dist, dist + n+1, inf);//dist数组初始化为inf dist[s] = 0;//将起点的dist设为0 for (int i = 1; i <= n; i++)//因为从起点开始,所以执行n次 { int u = -1, min = inf; for (int j = 1; j <= n; j++)//寻找最短边 { if (!visited[j] && dist[j] < min) { u = j; min = dist[j]; } } if (u == -1)return; visited[u] = 1;//这里不能忘记 for (int j = 1; j <= n; j++) { if (!visited[j]) { if (min + edges[u][j] < dist[j]) dist[j] = min + edges[u][j]; } } } } int main() { std::ios::sync_with_stdio(false); std::cin.tie(0); std::cout.tie(0); cin >> n >> m >> s; fill(edges[0], edges[0] + 10002 * 10002, inf);//这种写法在数据量比较大的题目中是会爆内存的 for (int i = 1; i <= m; i++) { int a, b,c; cin >> a >> b >> c; edges[a][b] = c; } Dijkstra(); for (int i = 1; i <= n; i++) printf("%s%d", i == 1 ? "" : " ", dist[i]); }
防止爆内存Dijkstra
题目:https://www.luogu.com.cn/problem/P3371
本题目数据量
但是还是TLE………………
于是使用vector储存图,详见代码
代码
//改进vector版Dijkstra #include<iostream> #include<queue> #include<algorithm> #include<cstdio> #include<cmath> #include<vector> using namespace std; typedef pair<int, int> p; //这里最好使用typedef 定义一下下面再用,如果直接vector<pair<int,int>> edges[10002];在OJ编程通不过………… //priority_queue<pair<int, int> > qq; // 注意在两个尖括号之间一定要留 空格,防止误判 vector<p> edges[10002]; long long dist[10002]; int visited[10002]; #define inf 0x3f3f3f3f int n, m, s; void Dijkstra() { fill(dist, dist + n+1, inf); dist[s] = 0; for (int i = 1; i <= n; i++) { int u = -1; long long min = inf; for (int j = 1; j <= n; j++) { if (!visited[j] && dist[j] < min) { u = j; min = dist[j]; } } if (u == -1)return; visited[u] = 1; for (int j = 0; j <edges[u].size(); j++)//在以u为起点的所有边中寻找 { int vv = edges[u][j].first;//是这条边的终点 if (!visited[vv]) { if (min + edges[u][j].second< dist[vv]) dist[vv] = min + edges[u][j].second; } } } } int main() { std::ios::sync_with_stdio(false); std::cin.tie(0); std::cout.tie(0); cin >> n >> m >> s; for (int i = 1; i <= m; i++) { int a, b, c; cin >> a >> b >> c; edges[a].push_back(make_pair(b, c));//使用每条边的起始节点作为edges的index,pair里是终点与权值 } Dijkstra(); bool space = false; for (int i = 1; i <= n; i++) { if (visited[i]) printf("%s%d",space==false?"":" ", dist[i]); else printf("%s%s", space == false ? "" : " ", "2147483647"); space = true; } } //测试实例 //5 15 5 //2 2 270 //1 4 89 //2 1 3 //5 5 261 //5 2 163 //5 5 275 //4 5 108 //4 4 231 //3 4 213 //3 3 119 //3 1 77 //3 1 6 //2 4 83 //5 5 196 //5 5 94 //166 163 2147483647 246 0
Dijkstra堆优化
题目:https://www.luogu.com.cn/problem/P4779
#include<iostream> #include<queue> #include<algorithm> #include<cstdio> #include<cmath> using namespace std; #define maxn 100010 #define maxm 500010 #define inf 0x7fffffff struct edge { int to;//终点 int dis;//权值 int next;//下一条边 //不添加from起点,意义不大 }; struct node { int dis;//权值 int pos;//下标 bool operator <(const node &x)const { return x.dis < dis;//从小到大排序 } }; edge e[maxm]; int head[maxn], dist[maxn], cnt, visited[maxn]; int n, m, s; priority_queue<node>q;//每次出队的都是dis最小的,节省了(更新后再比,出现更小的再更新此类情况)消耗的时间 void addedge(int u, int v, int w) { cnt++; e[cnt].dis = w; e[cnt].to = v; e[cnt].next = head[u];//head[u]总是临时存放着同起点的前一条边,当同起点的后一条边输入时,把前一条边的index赋值给这条边的next(于是同起点的边顺序是输入顺序的反序) head[u] = cnt; } void Dijkstra() { fill(dist, dist + n + 1, inf); dist[s] = 0; q.push({ 0, s });//加入起点 while (!q.empty()) { node tmp = q.top(); q.pop(); int x = tmp.pos, d = tmp.dis; if (visited[x])continue; visited[x] = 1;//相当于前面的visited[u] = 1; for (int i = head[x]; i; i = e[i].next) { int y = e[i].to; if (dist[y] > dist[x] + e[i].dis) { dist[y] = dist[x] + e[i].dis; q.push({ dist[y], y }); } } } } int main() { std::ios::sync_with_stdio(false); std::cin.tie(0); std::cout.tie(0); cin >> n >> m >> s; for (int i = 1; i <= m; i++) { int a, b, c; cin >> a >> b >> c; addedge(a, b, c); } Dijkstra(); for (int i = 1; i <= n; i++) printf("%s%d", i == 1 ? "" : " ", dist[i]); }