L2-1. 紧急救援(dijkstra单源最短路径拓展应用)

L2-1. 紧急救援

时间限制
200 ms
内存限制
65536 kB
代码长度限制
8000 B
判题程序
Standard
作者
陈越
作为一个城市的应急救援队伍的负责人,你有一张特殊的全国地图。在地图上显示有多个分散的城市和一些连接城市的快速道路。每个城市的救援队数量和每一条连接两个城市的快速道路长度都标在地图上。当其他城市有紧急求助电话给你的时候,你的任务是带领你的救援队尽快赶往事发地,同时,一路上召集尽可能多的救援队。

输入格式:

输入第一行给出4个正整数N、M、S、D,其中N(2<=N<=500)是城市的个数,顺便假设城市的编号为0~(N-1);M是快速道路的条数;S是出发地的城市编号;D是目的地的城市编号。第二行给出N个正整数,其中第i个数是第i个城市的救援队的数目,数字间以空格分隔。随后的M行中,每行给出一条快速道路的信息,分别是:城市1、城市2、快速道路的长度,中间用空格分开,数字均为整数且不超过500。输入保证救援可行且最优解唯一。

输出格式:

第一行输出不同的最短路径的条数和能够召集的最多的救援队数量。第二行输出从S到D的路径中经过的城市编号。数字间以空格分隔,输出首尾不能有多余空格。

输入样例:
4 5 0 3
20 30 40 10
0 1 1
1 3 2
0 3 3
0 2 2
2 3 2
输出样例:
2 60
0 1 3

题解:dijkstra单源最短路径拓展应用.

AC代码:

#include<iostream>
#include<memory.h>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<cstdlib>
#include<iomanip>
#include<algorithm>
typedef long long LL;
using namespace std;

const int maxn = 500 + 10, INF = 0x3f3f3f3f;
int N, M, S, D;
//val用于存人数,dis存到S的最短距离,map存图,cntp存当前点最短路径条数
//num存到当前点最多召集的人数,path存当前点的前驱用于最后输出路径
int val[maxn], dis[maxn], map[maxn][maxn], cntp[maxn], num[maxn], path[maxn];
bool vis[maxn];

void dijstra(int s) {
    //初始化
    for (int i = 0; i < N; i++) {
        dis[i] = INF;
    }
    for (int i = 0; i < N; i++) {
        path[i] = i;
    }
    memset(cntp, 0, sizeof(cntp));
    memset(num, 0, sizeof(num));
    memset(vis, false, sizeof(vis));
    dis[s] = 0;
    cntp[s] = 1;
    num[s] = val[s];  

    for (int i = 0; i < N; i++) {
        if (i != s) {
            dis[i] = map[s][i];
            if (map[s][i] != INF) {  

                cntp[i] = 1;
                num[i] = val[i] + num[s];
                path[i] = s;
            }
        }
    }
    vis[s] = true;
    //初始化完毕

    for (int t = 0; t < N - 1; t++) {
        int minn = INF, index = s;
        for (int i = 0; i < N; i++) {
            if (!vis[i] && minn > dis[i]) { //注意!vis[i]
                minn = dis[i];
                index = i;
            }
        }
        vis[index] = true;  

        for (int i = 0; i < N; i++) {
            if (!vis[i] && map[index][i] < INF) {   //debug add !vis[i]

                //不判断vis[i]去重的话会使下一句dis[index] + map[index][i] == dis[i]即 

                //dis[index] + 0 == dis[i] (i == index时) 为真,重复计算 

                if (dis[index] + map[index][i] == dis[i]) {  

                    cntp[i] += cntp[index]; //debug 不是简单的cntp[i]++,index之前可能连接着多条路径 

                    if (num[index] + val[i] > num[i]) {  

                        num[i] = val[i] + num[index];
                        path[i] = index;
                    }
                } 

                //此处没判不判断!vis[i]无所谓,是因为即使index == i时,dis[index] < dis[i]肯定不成立
                else if (dis[index] + map[index][i] < dis[i])
                 {
                    cntp[i] = cntp[index];    //debug 重新计算最短路径数

                    dis[i] = dis[index] + map[index][i];  

                    num[i] = val[i] + num[index];  

                    path[i] = index;
                }
            }
        }
    }
}

int main()
{
    scanf("%d%d%d%d", &N, &M, &S, &D);
    for (int i = 0; i < N; i++) {
        scanf("%d", &val[i]);
    }
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            map[i][j] = (i == j ? 0 : INF);
        }
    }
    for (int i = 0; i < M; i++) {
        int u, v, w;
        scanf("%d%d%d", &u, &v, &w);
        map[u][v] = map[v][u] = w;
    }
    dijstra(S);

    printf("%d %d\n", cntp[D], num[D]);

    int pre[maxn], i, len; //用pre相当于一个栈的作用,根据path输出最后结果
    i = D; len = 0;
    while (i != S) {
        pre[len++] = i;
        i = path[i];
    }
    pre[len++] = i;

    for (int j = len - 1; j >= 0; j--) {
        printf(j == len - 1 ? "%d" : " %d", pre[j]);
    }
    puts("");
    return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Dijkstra算法是一种用于计算图中单源最短路径的贪心算法。下面是Java实现Dijkstra算法的示例代码: ```java import java.util.*; public class DijkstraAlgorithm { private static final Graph.Edge[] GRAPH = { new Graph.Edge("A", "B", 7), new Graph.Edge("A", "D", 5), new Graph.Edge("B", "C", 8), new Graph.Edge("B", "D", 9), new Graph.Edge("B", "E", 7), new Graph.Edge("C", "E", 5), new Graph.Edge("D", "E", 15), new Graph.Edge("D", "F", 6), new Graph.Edge("E", "F", 8), new Graph.Edge("E", "G", 9), new Graph.Edge("F", "G", 11) }; private static final String START = "A"; private static final String END = "G"; public static void main(String[] args) { Graph graph = new Graph(GRAPH); graph.dijkstra(START); System.out.println(graph.getPath(END)); } static class Graph { private final Map<String, Vertex> graph; static class Edge { final String v1, v2; final int dist; Edge(String v1, String v2, int dist) { this.v1 = v1; this.v2 = v2; this.dist = dist; } } static class Vertex implements Comparable<Vertex> { final String name; int dist = Integer.MAX_VALUE; Vertex previous = null; final Map<Vertex, Integer> neighbours = new HashMap<>(); Vertex(String name) { this.name = name; } private void printPath() { if (this == this.previous) { System.out.printf("%s", this.name); } else if (this.previous == null) { System.out.printf("%s(unreached)", this.name); } else { this.previous.printPath(); System.out.printf(" -> %s(%d)", this.name, this.dist); } } public int compareTo(Vertex other) { return Integer.compare(dist, other.dist); } } Graph(Edge[] edges) { graph = new HashMap<>(edges.length); for (Edge e : edges) { if (!graph.containsKey(e.v1)) graph.put(e.v1, new Vertex(e.v1)); if (!graph.containsKey(e.v2)) graph.put(e.v2, new Vertex(e.v2)); } for (Edge e : edges) { graph.get(e.v1).neighbours.put(graph.get(e.v2), e.dist); } } void dijkstra(String startName) { if (!graph.containsKey(startName)) { System.err.printf("Graph doesn't contain start vertex \"%s\"\n", startName); return; } final Vertex source = graph.get(startName); NavigableSet<Vertex> q = new TreeSet<>(); for (Vertex v : graph.values()) { v.previous = v == source ? source : null; v.dist = v == source ? 0 : Integer.MAX_VALUE; q.add(v); } dijkstra(q); } private void dijkstra(final NavigableSet<Vertex> q) { Vertex u, v; while (!q.isEmpty()) { u = q.pollFirst(); if (u.dist == Integer.MAX_VALUE) break; for (Map.Entry<Vertex, Integer> a : u.neighbours.entrySet()) { v = a.getKey(); final int alternateDist = u.dist + a.getValue(); if (alternateDist < v.dist) { q.remove(v); v.dist = alternateDist; v.previous = u; q.add(v); } } } } List<String> getPath(String endName) { if (!graph.containsKey(endName)) { System.err.printf("Graph doesn't contain end vertex \"%s\"\n", endName); return Collections.emptyList(); } return graph.get(endName).printPath(); } } } ``` 该示例代码实现了一个简单的图,其中包含了一些边和顶点。在main方法中,我们创建了一个Graph对象,并调用了它的dijkstra方法来计算从起点到终点的最短路径。最后,我们打印出了这条路径。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值