【做练习】附近编号最大的城市(有源最短路Dijkstra算法)

这是在openjudge百练上看到的一道练习题,我看到通过率有点儿低,以为会有点儿难度。实际上是个送分题。

题目

描述

有N(不大于10)座城市,编号为1至N,已知任意两个城市间直接距离(不超过1000的非负整数)。求距离(直接或间接)城市1不超过K(K为小于100的正整数)的所有城市中编号最大的是哪座。

输入

第一行输入一个整数n
第二行输入一个整数K
之后n行,每行n个整数,描述了城市间距离的邻接矩阵,其中第i行第j个表示城市i到城市j的距离。相邻整数用空格分开。

输出

距离不超过K的城市的最大编号

样例

Input:

3
3
0 1 4
1 0 3
4 3 0

Output:

2

分析

经典的非负权有向图的有源最短路,使用Dijkstra算法求解。
简单地说,Dijkstra算法,就是:

  1. 将所有的节点分为两组,一组是已知最短路的(记为A),一组是未知最短路的(记为B)。最初所有节点都在B中。
  2. 记录一个距离数组D[N],表示从源src到其它所有点的“已计算的最短距离”。如果一个点 i 在组A中,那么D[i]就表示了最短路的距离。如果点 i 在组B当中,D[i]表示的距离是待计算优化的。
  3. 初始化时,D[源] = 0,D[其它节点]=无穷大
  4. 循环:每次从B组找到一个 i ∈ B   m i n i m i z e   D [ i ] i \in B\ minimize\ D[i] iB minimize D[i],将 i i i放到A组去。并对所有和 i i i有邻接的节点 j j j,令 D [ j ] ← m i n { D [ i ] + c o s t [ i , j ] , D [ j ] } D[j]\leftarrow min\{D[i]+cost[i,j], D[j]\} D[j]min{D[i]+cost[i,j],D[j]},更新优化B组的D数组数值。
  5. 循环直到直到B组为空,或B组找不到可达源的节点(即 D [ i ] = + ∞ D[i] = +\infty D[i]=+)。此时数组D就是源到其它所有节点的最短路长度。

代码

测试样例应该非常简单,所以1ms就过了。在Dijkstra函数中使用了lambda表达式提高可读性,证明了openjudge评测系统支持C++ 11特性。

// Reference

#include 
#pragma warning(disable: 4996) //make Visual Studio happy

// Macros

# define MAX_N 10
# define INF 0x7FFFFFFF
 
# define min(x,y) (x < y ? x : y)
# define max(x,y) (x > y ? x : y)
# define isinf(x) (x == INF)

// Globals

int N;
int K;
int weight[MAX_N][MAX_N]; //direct distance between cities
// For dijkstra algotithm
int dis[MAX_N];

// IO

void Input()
{
    scanf("%d %d", &N, &K);
    for (int i = 0; i < N; i++)
        for (int j = 0; j < N; j++)
            scanf("%d", &weight[i][j]);
}

// Solutions

void Dijkstra(int src)
{

    // init
    bool* certained = new bool[N]; /* certioned[i] : whether the min distance
                                   * of city i is certianed? */
    for (int i = 0; i < N; i++){dis[i] = INF;
                                certained[i] = false;}
    dis[src] = 0;
    auto FindMinUncertained = [certained]() -> int {
        int mindis = INF, minIdx = -1;
        for (int i = 0; i < N; i++) if (!certained[i] && dis[i] < mindis)
        {
            mindis = dis[i];
            minIdx = i;
        }
        return minIdx;
    };

    // compute
    int idx;
    while ((idx = FindMinUncertained()) >= 0)
    {
        certained[idx] = true;
        for (int i = 0; i < N; i++) if (!certained[i])
        {
            dis[i] = min(dis[i], dis[idx] + weight[idx][i]);
        }
    }

}

// Find the city with maximum distance <= K

int FindMaxDistanceBelowK()
{
    int maxdis = -INF; int maxidx;
    for (int i = 0; i < N; i++) if (dis[i] <= K && dis[i] > maxdis)
    {
        maxdis = dis[i];
        maxidx = i;
    }
    return maxidx + 1; // plus 1 because the city number begins from 1
}


// Main


int main()
{
    Input();
    Dijkstra(0); // 0 denotes city #1
    printf("%d", FindMaxDistanceBelowK());
    return 0;
}

你可能感兴趣的:(【做练习】附近编号最大的城市(有源最短路Dijkstra算法))