PTA 7-35 inter city emergency rescue (25 points (s))

Posted by exa_bit on Fri, 24 Dec 2021 01:22:47 +0100

As the head of a city's emergency rescue team, you have a special national map. The map shows multiple scattered cities and some expressways connecting cities. The number of rescue teams in each city and the length of each expressway connecting the two cities are marked on the map. When other cities have emergency calls for you, your task is to lead your rescue team to catch up with the accident as soon as possible, and at the same time, call as many rescue teams as possible along the way.

Input format:

Input the first line to give four positive integers N, m, s and D, where N (2 ≤ N ≤ 500) is the number of cities. Incidentally, suppose that the number of cities is 0 ~ (N − 1); M is the number of expressways; S is the city number of the place of departure; D is the city number of the destination.

The second line gives N positive integers, where the ith number is the number of rescue teams in the ith City, and the numbers are separated by spaces. In the following M lines, each line gives the information of an expressway, namely: the length of city 1, city 2 and expressway, separated by spaces, and the numbers are integers and no more than 500. The input guarantees that the rescue is feasible and the optimal solution is unique.

Output format:

The first line outputs the number of shortest paths and the maximum number of rescue teams that can be convened. The second line outputs the city number passed in the path from S to D. Numbers are separated by spaces, and there must be no extra spaces at the end of the output.

Input example:

4 5 0 3
20 30 40 10
0 1 1
1 3 2
0 3 3
0 2 2
2 3 2

No blank lines at the end

Output example:

2 60
0 1 3

No blank lines at the end

#include <iostream>
#define INF 0x3f3f3f3f
#define MAXN 500
using namespace std;

int n, m, s, d;
int totalLen[MAXN];      //Record the shortest path from starting point S to city i
int totalRescue[MAXN];      //Record the maximum number of rescue teams summoned from starting point S to city i
int rescue[MAXN];        //Record the number of rescue teams in i city
int Len[MAXN][MAXN];      //Record the path length between the two cities
int cnt[MAXN];           //Record the number of shortest paths
int pre[MAXN];           //Record the precursor of i City
int vis[MAXN]{false};    //Mark whether to access

void print(int u){
    // Vertex = = starting point (recursive boundary, find the starting point)
    if(u == s){
        cout << u;
        return;
    }
    // Find the precursor node recursive output (recursive)
    print(pre[u]);
    cout << " " << u;
}

void Dijkstra(int s){
    totalLen[s] = 0;
    totalRescue[s] = rescue[s];
    cnt[s] = 1;
    // Update N-1 times, source point updated
    for(int i = 0; i < n-1; i++){
        int u, Min = INF;
        // Find nearest adjacency point
        for(int j = 0; j < n; j++)
            if(vis[j] == false && totalLen[j] < Min)
                u = j, Min = totalLen[j];
        vis[u] = true;
        // The connected graph does not need to judge whether it is disconnected and exit
        for(int v = 0; v < n; v++){
            // With the nearest adjacency point u as the intermediary, the vertex has not traversed the && path is shorter
            if(vis[v] == false && totalLen[v] > totalLen[u] + Len[u][v]){
                // Update source point s to other vertex path length = s - > U + U - > V 
                totalLen[v] = totalLen[u] + Len[u][v];
                // Rescue team
                totalRescue[v] = totalRescue[u] + rescue[v];
                // Number of shortest paths
                cnt[v] = cnt[u];
                // Passing city
                pre[v] = u;
            }
            // Same path length
            else if(vis[v] == false && totalLen[v] == totalLen[u] + Len[u][v]){
                // The shortest path is not unique 
                cnt[v] += cnt[u];
                // More rescue teams
                if(totalRescue[v] < totalRescue[u] + rescue[v]){
                    totalRescue[v] = totalRescue[u] + rescue[v];
                    pre[v] = u;
                }
            }
        }
    }
};

int main() {
    // Initialization path length and city shortest path
    fill(*Len, *Len + MAXN * MAXN, INF);
    fill(totalLen, totalLen + MAXN, INF);
    cin >> n >> m >> s >> d;
    // Read the number of rescue teams and path length
    for(int i = 0; i < n; i++){
        cin >> rescue[i];
    }
    for(int i = 0; i < m; i++){
        int c1, c2, len;
        cin >> c1 >> c2 >> len;
        Len[c1][c2] = Len[c2][c1] = len;
    }
    Dijkstra(s);
    // Output the shortest path and the maximum number of rescue teams
    cout << cnt[d] << " " << totalRescue[d] << endl;
    // Export route City
    print(d);
}

cnt[to] += cnt[pass];

Think about why you want to accumulate the previous paths here. If there is no initialization, all CNTs are 0. So add this code to the judgment of the update path length and the same path to see what happens.

cout << totalLen[to] << " " << pass << " " << to << " " << cnt[pass] << " " << cnt[to] << endl;

You can see the update from source point 0 to end point 3. There are 0 - > 3 and 1 - > 3 with the same path length, both of which are the first 3. At this time, there are two paths to destination 3, and if other points pass through 3 to other destinations, 2 will be added. The following nodes are similar, so you can know why + =.

Reference code

Topics: Algorithm data structure Graph Theory