PTA 1003 Emergency PAT甲级真题 题目解析

20 篇文章 2 订阅
9 篇文章 0 订阅

PTA-mooc完整题目解析及AC代码库:PTA(拼题A)-浙江大学中国大学mooc数据结构全AC代码与题目解析(C语言)

之前一直没做图这章的附加编程题,现在把整个课程学完之后再重新回来补上吧。不过好像这一章的几乎都是最短路的问题,挑几个写写题解好了。


As an emergency rescue team leader of a city, you are given a special map of your country. The map shows several scattered cities connected by some roads. Amount of rescue teams in each city and the length of each road between any pair of cities are marked on the map. When there is an emergency call to you from some other city, your job is to lead your men to the place as quickly as possible, and at the mean time, call up as many hands on the way as possible.

Input Specification:

Each input file contains one test case. For each test case, the first line contains 4 positive integers: N (≤500) - the number of cities (and the cities are numbered from 0 to N−1), M - the number of roads, C 1 C_1 C1 and C 2 C_2 C2 - the cities that you are currently in and that you must save, respectively. The next line contains N integers, where the i-th integer is the number of rescue teams in the i-th city. Then M lines follow, each describes a road with three integers c 1 c_1 c1, c 2 c_2 c2 and L, which are the pair of cities connected by a road and the length of that road, respectively. It is guaranteed that there exists at least one path from C 1 C_1 C1 to C 2 C_2 C2.

Output Specification:

For each test case, print in one line two numbers: the number of different shortest paths between C1 and C2, and the maximum amount of rescue teams you can possibly gather. All the numbers in a line must be separated by exactly one space, and there is no extra space allowed at the end of a line.

Sample Input:

5 6 0 2
1 2 1 5 3
0 1 1
0 2 2
0 3 1
1 2 1
2 4 1
3 4 1

Sample Output:

2 4

题目分析

给定一个城市地图,每个城市都有一些急救队,求当给定起点和终点城市时,走过的最短路径条数和沿途聚集的最大急救队数量。

没啥说的,典型的单源最短路径问题,碰到首先想到就是Dijkstra算法,当然其他的图遍历算法也可以做。

碰到这种城市地图之类的问题时候,通常把图存为邻接表要比邻接矩阵好一些,毕竟乘机公路的数量在实际生活中一定是远小于城市数量的。

具体算法过程中,把Dijkstra算法中取最小距离结点放入集合中这一步进行微调即可。若A到B有路,则当取A放入集合时

  • 如果源点到A的路径长度加上AB间路径长度小于B当前的路径长度,则更新B的路径长度为源点到A的路径长度加上AB间路径长度,并且将到A的最短路径数量赋值给B,然后更新到达B时经过A聚集的总急救队数量
  • 如果源点到A的路径长度加上AB间路径长度等于B当前的路径长度,说明经过A到B是一条最短路,而且除了A以外,还有经过其他点到达B的最短路。此时,在B已累计的最短路径数量上加上经过A的路径数。注意,当有多条最短路时,还需计算所有最短路中最大的聚集急救队数量。

最后打印终点结点对应的最短路数量以及聚集的急救队数量即可。


#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

#define INFINITY 65535
#define ERROR -1
/* ——————无向图的邻接表定义开始—————— */
#define MaxVertexNum 500
typedef int Vertex;
typedef int WeightType;
typedef int DataType;

typedef struct ENode *PtrToENode;
struct ENode{
    Vertex V1, V2;
    WeightType RoadLength;  // 路的长度
};
typedef PtrToENode Edge;

typedef struct AdjVNode *PtrToAdjVNode;
struct AdjVNode{
    Vertex AdjV;
    WeightType RoadLength;  // 路的长度
    PtrToAdjVNode Next;
};

typedef struct Vnode{
    PtrToAdjVNode FirstEdge;
    DataType RescueNum;     // 急救队数量
} AdjList[MaxVertexNum];

typedef struct GNode *PtrToGNode;
struct GNode{
    int Nv;
    int Ne;
    AdjList G;
};
typedef PtrToGNode LGraph;

LGraph CreateGraph( int VertexNum );
void DestoryGraph( LGraph Graph );
void InsertEdge(LGraph Graph, Edge E);
/* ——————无向图的邻接表定义结束—————— */
Vertex source, destination;
bool collected[MaxVertexNum];   // 是否被收录
WeightType roadLength[MaxVertexNum];    // 路径长度
int shortestNum[MaxVertexNum];  // 最短路数量
DataType rescueNum[MaxVertexNum];   // 急救队数量

LGraph BuildGraph();
void init(LGraph Graph);
int FindMinDist(LGraph Graph);
void solve(LGraph Graph);

int main()
{
    LGraph graph;
    graph = BuildGraph();
    solve(graph);
    DestoryGraph(graph);

    return 0;
}

LGraph CreateGraph( int VertexNum )
{
    Vertex V;
    LGraph Graph;

    Graph = (LGraph)malloc(sizeof(struct GNode));
    Graph->Nv = VertexNum;
    Graph->Ne = 0;

    for (V = 0; V < Graph->Nv; ++V)
        Graph->G[V].FirstEdge = NULL;

    return Graph;
}

void DestoryGraph( LGraph Graph )
{
    Vertex V;
    PtrToAdjVNode Node;
    for (V = 0; V < Graph->Nv; ++V) {
        while (Graph->G[V].FirstEdge) {
            Node = Graph->G[V].FirstEdge;
            Graph->G[V].FirstEdge = Node->Next;
            free(Node);
        }
    }
    free(Graph);
}

void InsertEdge(LGraph Graph, Edge E)
{
    PtrToAdjVNode NewNode;

    NewNode = (PtrToAdjVNode)malloc(sizeof(struct AdjVNode));
    NewNode->AdjV = E->V2; NewNode->RoadLength = E->RoadLength;
    NewNode->Next = Graph->G[E->V1].FirstEdge;
    Graph->G[E->V1].FirstEdge = NewNode;

    NewNode = (PtrToAdjVNode)malloc(sizeof(struct AdjVNode));
    NewNode->AdjV = E->V1; NewNode->RoadLength = E->RoadLength;
    NewNode->Next = Graph->G[E->V2].FirstEdge;
    Graph->G[E->V2].FirstEdge = NewNode;
}

LGraph BuildGraph()
{
    LGraph graph;
    Edge E;
    Vertex V;
    int Nv, i;

    scanf("%d", &Nv);
    graph = CreateGraph(Nv);
    scanf("%d", &(graph->Ne));
    scanf("%d %d", &source, &destination);
    for (V = 0; V < Nv; ++V)
        scanf("%d", &(graph->G[V].RescueNum));
    if (graph->Ne != 0) {
        E = (Edge)malloc(sizeof(struct ENode));
        for (i = 0; i < graph->Ne; ++i) {
            scanf("%d %d %d", &(E->V1), &(E->V2), &(E->RoadLength));
            InsertEdge(graph, E);
        }
        free(E);
    }

    return graph;
}

void init(LGraph Graph)
{
    Vertex V;
    for (V = 0; V < Graph->Nv; ++V) {
        collected[V] = false;
        roadLength[V] = INFINITY;
        shortestNum[V] = 0;
    }
}

int FindMinDist(LGraph Graph)
{
    Vertex MinV, V;
    int MinDist = INFINITY;

    for (V = 0; V < Graph->Nv; ++V) {
        if (!collected[V] && roadLength[V] < MinDist) {
            MinDist = roadLength[V];
            MinV = V;
        }
    }
    if (MinDist < INFINITY) return MinV;
    else return ERROR;
}

void solve(LGraph Graph)
{
    PtrToAdjVNode edge;
    Vertex V;

    init(Graph);
    // 先将源点放入已取元素的集合中,然后更改其邻接点相关值
    collected[source] = true; roadLength[source] = 0;
    shortestNum[source] = 1; rescueNum[source] = Graph->G[source].RescueNum;
    for (edge = Graph->G[source].FirstEdge; edge; edge = edge->Next) {
        roadLength[edge->AdjV] = edge->RoadLength;
        shortestNum[edge->AdjV] = shortestNum[source];
        rescueNum[edge->AdjV] = rescueNum[source] + Graph->G[edge->AdjV].RescueNum;
    }
    // 然后依次从未取元素中找距离最小的元素放入集合中
    while (true) {
        V = FindMinDist(Graph);
        if (V == ERROR || V == destination)
            break;
        collected[V] = true;
        for (edge = Graph->G[V].FirstEdge; edge; edge = edge->Next) {
            if (!collected[edge->AdjV]) {
                if (roadLength[V] + edge->RoadLength < roadLength[edge->AdjV]) {
                    roadLength[edge->AdjV] = roadLength[V] + edge->RoadLength;
                    shortestNum[edge->AdjV] = shortestNum[V];
                    rescueNum[edge->AdjV] = rescueNum[V] + Graph->G[edge->AdjV].RescueNum;
                }
                else if (roadLength[V] + edge->RoadLength == roadLength[edge->AdjV]) {
                    shortestNum[edge->AdjV] += shortestNum[V];
                    if (rescueNum[edge->AdjV] < rescueNum[V] + Graph->G[edge->AdjV].RescueNum)
                        rescueNum[edge->AdjV] = rescueNum[V] + Graph->G[edge->AdjV].RescueNum;
                }
            }
        }
    }
    printf("%d %d\n", shortestNum[destination], rescueNum[destination]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值