先来看这样一道题目
给你N个点,M条双向边,要求求出1号点到其他所有点的距离。其中 2 <= N <= 1e5, 1 <=M <= 1e6.
对于这样的一道题目 我们当然不可能开一个数组edge[N][N]来记录边的信息,根本不可能开的下。
假如开下了也会有很多边为-1,浪费了很多空间。 所以可以对存边的方式进行优化。
优化1: 对边进行优化。
因为edge[N][N]的空间需要N^2大小,当N稍微大一点点的时候,就没办法开这么大的空间。
并且由于当边的分布比较散的时候,我们每次找到一个新的最小点之后,都要遍历他所有的边去更新d[]数组,
然而当边分布分散的时候,我们会花大部分时间在不存在的边上。
在这里我们用链式前向星来存边,这样可以使得存边的空间大大减小,并且每次更新的时候遍历的边都是真正存在的边,不会在访问那些不存在的边。
链式前向星优化
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<algorithm> 5 using namespace std; 6 const int N = 105; 7 const int M = 10010 * 2; 8 const int inf = 0x3f3f3f3f; 9 int d[N]; 10 bool vis[N]; 11 int head[N]; 12 int nt[M], to[M], w[M]; 13 int tot; 14 void init(){ 15 memset(head, -1, sizeof(head)); 16 tot = 0; 17 } 18 void add(int u, int v, int val){ 19 to[tot] = v; 20 w[tot] = val; 21 nt[tot] = head[u]; 22 head[u] = tot++; 23 } 24 int main() 25 { 26 int n, m; 27 while(~scanf("%d%d",&n,&m)&& (n || m)){ 28 int a,b,c; 29 init(); 30 memset(d, inf, sizeof(d)); 31 memset(vis, 0, sizeof(vis)); 32 while (m--){ 33 scanf("%d%d%d", &a, &b, &c); 34 add(a,b,c); 35 add(b,a,c); 36 } 37 d[1] = 0; 38 while (1){ 39 int min1 = inf,z = -1; 40 for (int j = 1;j <= n; j++) 41 if(!vis[j] && min1 > d[j]) 42 z = j, min1 = d[j]; 43 if(z == -1) break; 44 vis[z] = 1; 45 for (int j = head[z]; ~j; j = nt[j]){ 46 d[to[j]] = min(d[to[j]], d[z] + w[j]); 47 } 48 } 49 printf("%d\n", d[n]); 50 } 51 return 0