最短路
P3371 单源最短路径(弱化版)
- dij 空间超限
#include<bits/stdc++.h>
using namespace std;
int n , m , s ;
const int N = 1e4 ;
int g[N][N] ;
int d[N] ;
bool v[N] ;
int main(){
memset(g, 0x3f, sizeof g) ;
scanf("%d%d%d",&n,&m,&s) ;
for(int i = 0 ; i < m ; i ++){
int a , b , c ;
scanf("%d%d%d",&a,&b,&c) ;
g[a][b] = c ;
}
// dij() ;
memset(d, 0x3f, sizeof d);
d[s] = 0 ;
for(int i = 0 ; i < n ; i ++){
int t = -1 ;
for(int j = 1 ; j <= n ; j ++){
if(!v[j] && (d[j] < d[t]|| t == -1)){
t = j ;
}
}
v[t] = true ;
for(int j = 1 ; j <= n ; j ++){
d[j] = min(d[j], d[t] + g[t][j]) ;
}
}
for(int i = 1 ; i <= n ; i ++){
if(d[i] != 0x3f3f3f3f) printf("%d ",d[i]) ;
else cout << pow(2,31) - 1 << " " ;
}
return 0 ;
}
针对 dij 有两种优化解决方案:
- dij + 链式前向星 边优化
#include<bits/stdc++.h>
using namespace std;
struct edge{
int next ;
int to ;
int w ;
}e[maxsize] ;
int head[maxsize] ;
int cnt = 0 ;
void add(int u, int v, int w){
cnt ++ ;
e[cnt].next = head[u] ; // 头结点的上一个孩子成了当前孩子的兄弟
e[cnt].to = v ; // 结点连向 v
e[cnt].w = w ;
head[u] = cnt ; //更新孩子
}
int main(){
int n ;
for(int i = 1 ; i <= n ; i ++){
int a, b, w ;
add(a,b,w) ; // 如果无向,还要add(b,a,w)
}
return 0 ;
}
“既可以存图,也可以存树,比起邻接矩阵,链式前向星的空间复杂度是O(n),大大节省了存储空间,因为按边存储省掉了很多两点无边的空间。并且在遍历的时候,那些与起点无边相连的点也不需要进行处理,可以说时间和空间都占优势”
#include<bits/stdc++.h>
using namespace std;
const int maxsize = 1e6 + 10 ;
int head[maxsize] ;
int cnt = 0 ;
int ans[maxsize] ;
bool v[maxsize] ;
int n , m , s ;
struct edge{
int next ; // 兄弟的index
int to ; // 存放的结点
int w ; // 边的权重
}e[maxsize] ;
void add(int u, int v, int w){
cnt ++ ;
e[cnt].next = head[u] ; // 头结点的上一个孩子成了当前孩子的兄弟
e[cnt].to = v ; // 结点连向 v
e[cnt].w = w ;
head[u] = cnt ; //更新孩子
}
int main(){
scanf("%d%d%d",&n, &m, &s) ;
memset(e, 0, sizeof(struct edge) * maxsize ) ; //对结构体数组初始化
//memset(&e, 0, sizeof(struct edge)) ; //对结构体变量初始化 **&**
for(int i = 1 ; i <= m ; i ++){
int a, b, w ;
scanf("%d%d%d",&a,&b,&w) ;
add(a,b,w) ; // 如果无向,还要add(b,a,w)
}
memset(ans, 0x3f, sizeof ans) ;
ans[s] = 0 ;
int pre = s ;
while(!v[pre]){ // dij
int tepmin = 0x3f3f3f3f ;
v[pre] = true ;
for(int i = head[pre] ; i != 0 ; i = e[i].next){
if(!v[e[i].to] && ans[e[i].to] > ans[pre] + e[i].w){
ans[e[i].to] = ans[pre] + e[i].w ;
}
}// 更新所有子节点的答案
for(int i = 1 ; i <= n ; i ++){
if(ans[i] < tepmin && !v[i]){
tepmin = ans[i] ;
pre = i ;
}
}// 找最小结点
}
for(int i = 1 ; i <= n ; i ++){
if(ans[i] != 0x3f3f3f3f) printf("%d ",ans[i]) ;
else cout << pow(2,31) - 1 << " " ;
}
return 0 ;
}