这样写答案不对

#include <iostream>

using namespace std;

const int mod = 100000;
const int INF = 100000000;
const int N = 100;

int n, m;
int path[N][N];
int dis[N];
int vis[N];

void init(){
    for(int i = 0; i < n; i++){
        for(int j = 0; j < n; j++){
            path[i][j] = INF;
        }
        dis[i] = INF;
    }
}

void Djikstra(int s){
    int i, j;
    for(i = 0; i < n; i++){
        dis[i] = path[s][i];
        vis[i] = 0;
    }
    dis[s] = 0;
    vis[s] = 1;
    int mindis, minnode;
    for(i = 0; i < n; i++){
        mindis = INF;
        minnode = 0;
        for(j = 0; j < n; j++){
            if(!vis[j] && mindis > dis[j]){
                minnode = j;
                mindis = dis[j];
            }
        }
        if(mindis == INF) break;
        vis[minnode] = 1;
        for(j = 0; j < n; j++){
            if(!vis[j] && dis[j] > dis[minnode] + path[minnode][j]){
                dis[j] = (dis[minnode] + path[minnode][j]);
            }
        }
    }
}

int main(){
    int from, to;
    while(cin >> n >> m){
        init();
        int len = 1;
        for(int i = 0; i < m; i++){
            cin >> from >> to;
            if(path[from][to] > len) path[from][to] = path[to][from] = len;

            len = len * 2;
            len = len % mod;
        }
        Djikstra(0);
        for(int i = 1; i < n; i++){
            if(dis[i] == INF) printf("-1\n");
            else printf("%d\n", dis[i] % mod);
        }
    }
}

图片说明

图片说明

图片说明

注意到第k条路径的长度为2^K,则第k条路径的长度会大于前k-1条路径的总和。
由此我们可知两个推断:
(1)在添加第k条路径时,如果路径k连接的两个城市A 、B已经通过其他路径间接的连通了,那么第k条路径绝对不是AB间的最短路径(第k条路径之后的路径也不可能有比当前AB路径更短的路径了,因为第k条路径的长度会大于前k-1条路径的总和)
(2)在添加第k条路径时,如果路径k连接的两个城市A 、B是第一次被连通了(也就是说此前没有任何路径能连通AB,包括通过多条路径间接连通),那么路径k就是AB之间的最短距离了,因为以后不可能存在更短的路径连接AB,以后的单条路径只会越来越长。
通过上述的推断,我们可以利通过建立一个最小连通树的同时算出0号城市到各个城市的最小路径。
具体的算法:
(1)构造一个并查集,每个城市指向自己,二维数组d记录城市之间的距离,初始化为-1不可达,d[i][i]初始化为0
(2)取第一条路径,第一条路径连接了城市a、b,城市a、b间最短路径就是第一条路径,然后把a、b合并在一个集合里
(3)再取一条路径,
(一)如果这条边连接的城市c、d,已经在同一个集合里了(即已经联通了),那么当前的路径一定不是cd之间的最短路径了,忽略之(理由是推断(1)),继续看下一条路径。
(二)如果这条路径连接的城市c、d不在同一个集合里(之前没有联通过),很好,这条路径是cd之间的最短路径(理由是推断(2));除此之外我们还可以看看通过这条路径能不能让c集合里的城市到d集合里的城市之间的路径更短呢?即是不是d[i][j]>(d[i][C]+dist+d[D][j]) ?(注意i和C一个集合,D和j一个集合),如果是的话可以更新一下这个值。
(4)重复(3)直到所有路径都处理过了
0号城市到各个城市i的最小路径结果就是d[0][i]了

图片说明

这样写AC

#include <iostream>
#include <stdio.h>
#include <memory.h>

using namespace std;

const int mod = 100000;
const int INF = 100000000;
const int N = 102;

int n, m;
int path[N][N];
int father[N];
int vis[N];

void init(){
    for(int i = 0; i < n; i++){
        for(int j = 0; j < n; j++){
            path[i][j] = INF;
        }
        path[i][i] = 0; //对角线
        father[i] = i;
        vis[i] = 0;
    }
}

int find(int x){
    if(x != father[x]){
        father[x] = find(father[x]);
    }
    return father[x];
}

int main(){
    int from, to;
    while(cin >> n >> m){
        init();
        int len = 1;
        for(int i = 0; i < m; i++){
            cin >> from >> to;
            int x = find(from);
            int y = find(to);
            if(x != y){
                //由于代价特点,后面的大于前面所有代价之和,这样一旦连通,后面的在连接也没有意义
                father[x] = y;
                path[from][to] = path[to][from] = len;
            }
            len = len * 2;
            len = len % mod;
        }
        vis[0] = 1;
        int i, j;
        int mindis, minnode;
        for(i = 0; i < n; i++){
            mindis = 123123123;
            minnode = 0;
            for(j = 1; j < n; j++){
                if(!vis[j] && mindis > path[0][j]){
                    minnode = j;
                    mindis = path[0][j];
                }
            }
            vis[minnode] = 1;
            for(j = 1; j < n; j++){
                if(!vis[j] && path[0][j] > path[0][minnode] + path[minnode][j]){
                    path[0][j] = path[0][minnode] + path[minnode][j];
                }
            }
        }
        for(i = 1; i < n; i++){
            if(path[0][i] == INF) printf("-1\n");
            else printf("%d\n", path[0][i] % mod);
        }
    }
}