九度OJ 1100:最短路径 (最短路径)

时间限制:1 秒

内存限制:32 兆

特殊判题:

提交:4185

解决:619

题目描述:

N个城市,标号从0到N-1,M条道路,第K条道路(K从0开始)的长度为2^K,求编号为0的城市到其他城市的最短距离

输入:

第一行两个正整数N(2<=N<=100)M(M<=500),表示有N个城市,M条道路
接下来M行两个整数,表示相连的两个城市的编号

输出:

N-1行,表示0号城市到其他城市的最短路,如果无法到达,输出-1,数值太大的以MOD 100000 的结果输出。

样例输入:
4 4
1 2
2 3
1 3
0 1
样例输出:
8
9
11
来源:
2010年上海交通大学计算机研究生机试真题

思路:

此题的路径长度很特殊,不能用普通的数值来表示。可以用数组或字符串的方式来表示路径长度,同时定义相应的大整数运算。

但由于路径长度的特殊性,更简单的办法是求最小生成树,求的过程中顺便求得最短路径。

我开始用的第一种方法,需要考虑的细节较多,出错了几次,后来用第二种方法AC的。


代码:

#include <stdio.h>
#include <stdlib.h>
 
int rank[100] ;//记录每个树的深度
int pre[100];//记录每个点的父节点
int d[100][100];//记录各对间的距离
 
void initSet(int n)//初始化,将每个点的父节点设为自己,深度为1
{
    int i;
    for(i=0; i<n; i++)
    {
        rank[i] = 1;
        pre[i] = i;
        d[i][i] = 0;
    }
}
 
int findSet(int x)//找到每个点的父节点,并将这个点的父节点设置为数的根节点
{
    if(x != pre[x])
        pre[x] = findSet(pre[x]);
    return pre[x];
}
 
void unionSet(int a, int b)//合并树,
{
    int x = findSet(a);
    int y = findSet(b);
    if(x == y)//如果两个节点的父节点(树的根节点)是同一个,无需合并,直接跳过
        return;
    if(rank[x] >= rank[y])
    {
        rank[x] += rank[y];
        pre[y] = x;
    }
    else
    {
        rank[y] += rank[y];
        pre[x] = y;
    }//不是同一个树的的节点,小树合并到大树
}
 
int mod(int a, int b)//取模
{
    int ret = 1;
    while(b--)
        ret = (ret*a)%100000;
    return ret;
}
 
int main()
{
    int n, m, dist;
    int x, y, a, b;
    int i, j, k;
    while(scanf("%d%d", &n, &m)!=EOF)
    {
        initSet(n);
        for(i=0; i<m; i++)
        {
            scanf("%d%d", &x, &y);
            a = findSet(x);
            b = findSet(y);
            if(a == b)//二者已在同一个连通分量,距离定是最小了
                continue;
            dist = mod(2, i);//取模
            for(j=0; j<n; j++)//更新两个连通分量的各对经过中间对的距离
            {
                if(a != findSet(j))
                    continue;
                for(k=0; k<n; k++)
                {
                    if(b != findSet(k))
                        continue;
                    d[j][k] = d[k][j] = (d[j][x]+dist+d[y][k])%100000;
                }
            }
            unionSet(x, y);
        }
        x = findSet(0);
        for(i=1; i<n; i++)
            if(findSet(i) != x)
                printf("-1\n");
            else
                printf("%d\n", d[0][i]);
    }
}  
/**************************************************************
    Problem: 1100
    User: liangrx06
    Language: C
    Result: Accepted
    Time:10 ms
    Memory:952 kb
****************************************************************/



你可能感兴趣的:(C语言,最短路径,OJ,九度)