Dijsktra算法应用(PAT1003)

1003 Emergency(25 分)

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, C1 and 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 c1, 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 C1 to 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.

分析:

该题是一道典型的图的最短路径算法——Dijkstra算法的应用,同时在这之上,添加了对最大点权和以及最短路径数量的要求。

思路:

使用邻接矩阵存储图,使用Dijkstra求出最短路径,在求最短路径中,判断如果有一条路径与dist[]中最短路径相等,则路径数量加一,若在此基础上,点权和比原weight中更大,则更新weight。

import java.util.*;

/**
 * Created by Boolean on 2018/8/8.
 */
public class Main {
    private static final int infinity=99999;
    public static void main(String[] args)
    {
       Scanner scanner = new Scanner(System.in);
       int cities = scanner.nextInt();//城市——结点
       int roads = scanner.nextInt();//路径
       int current_city = scanner.nextInt();//源点
       int save_city = scanner.nextInt();//目标点
       int[] teams = new int[cities];//点权
       for(int i=0;i<cities;i++)teams[i] = scanner.nextInt();
       int[][] map = new int[cities][cities];//图,邻接矩阵
       int[] dist = new int[cities];//源点到每个vertex的最短距离
       int[] path = new int[cities];//最短路径路径
       int[] count = new int[cities];//最短路径的个数
       int[] weights = new int[cities];//最短路径下的最大点权和
       for(int i=0;i<cities;i++)
       {
           for(int j=0;j<cities;j++)
           {
               map[i][j] = infinity;
           }
       }
       for(int i=0;i<roads;i++)
       {
           int a = scanner.nextInt();
           int b = scanner.nextInt();
           int weight = scanner.nextInt();
           map[a][b] = weight;
           map[b][a] = weight;
       }
       //邻接矩阵输出
      /* for(int i=0;i<cities;i++)
       {
           for (int j=0;j<cities;j++)
               System.out.print(map[i][j]+"  ");
           System.out.println("\n");
       }
*/
        if(Dijkstra(current_city,map,dist,path,cities,count,teams,save_city,weights))
        {
            //输出最短路径数量与最大点权和
            System.out.printf("%d %d\n",count[save_city],weights[save_city]);
        }
        else
        {
            System.out.println("ERROR!"+"可能出现负值圈");
        }
       //最短路径输出
       /* int index = save_city;
        while(path[index]!=-1)
       {
           System.out.printf("%d ",path[index]);
           index = path[index];
       }
        System.out.printf("\n");*/

    }
    //找出当前距源点dist最小且未收录的节点
    //一般使用遍历(稠密)或最小堆
    private static int FindMinDist(int[][] map,int[] dist,Boolean[] collected,int cities)
    {
        int minDist = infinity;
        int min = -1;
        for(int i=0;i<cities;i++)
        {
            if(!collected[i]&&dist[i]<minDist)
            {
                min = i;
                minDist = dist[i];
            }
        }
        return min;
    }
    //Dijstra算法
    private static Boolean Dijkstra(int vertex,int[][] map,int[] dist,int[] path,int cities,int[] count,int[] teams,int save_city,int[] weights)
    {
        //初始化path,与源点邻接为weight,否则为-1
        //coolected记录节点是否已经被收录
        Boolean[] collected = new Boolean[cities];
        path[vertex] = -1;//源点路径为-1
        weights[vertex] = teams[vertex];//源点点权和为本身
        dist[vertex] = 0;
        collected[vertex] = true;//收录
        //初始化,遍历源点邻接的节点,初始化这些节点的path为源点,dist为源点与该点的权值,count全部初始化为1
        for(int i=0;i<cities;i++)
        {
            count[i] = 1;
            dist[i] = map[vertex][i];
           // System.out.println(i+"   "+dist[i]);
            if(dist[i]<infinity)
            {
                path[i] = vertex;
                weights[i] = weights[vertex] + teams[i];
            }
            else
                path[i] = -1;
            collected[i] = false;
        }
        //循环找未收录且距离源点最近的节点
        while (true)
        {

            int ver = FindMinDist(map,dist,collected,cities);
            //未找到代表已经全部完成,跳出循环
            if(ver==-1)
                break;
            collected[ver] = true;//收录
            for(int i=0;i<cities;i++)
            {
                //遍历该节点的所有邻接点
                if(!collected[i]&&map[ver][i]<infinity)
                {
                    if(map[ver][i]<0)return false;//防止负值圈
                    //若从该点到邻接点的距离小于当前dist中对应邻接点的值,更新dist为该点的dist+邻接点与该点边的权值
                    //更新weight为该点的weight+邻接点的点权
                    //邻接点路径数量与该点相同
                    //若从该点到邻接点的距离等于当前dist中对应邻接点的值,路径数量++
                    //若从该点到邻接点的距离等于当前dist中对应邻接点的值且点权和更大,更新点权和
                    if(dist[i] > (dist[ver] + map[ver][i]))
                    {
                        dist[i] = dist[ver]+map[ver][i];
                        path[i] = ver;//路径
                        weights[i] = weights[ver] + teams[i];//点权
                        count[i]=count[ver];
                    }else if(dist[i]==(dist[ver] + map[ver][i]))
                    {
                        //从该点到邻接点的距离等于当前dist中对应邻接点的值
                            count[i] = count[ver]+count[i];
                            if((weights[ver]+teams[i])>weights[i])
                            {
                                weights[i] = weights[ver]+teams[i];
                            }
                    }

                }
            }
        }
        return true;
    }

}

未完待续…

猜你喜欢

转载自blog.csdn.net/Boolean_starki/article/details/82177878
今日推荐