最短路径

173 阅读11分钟

PAT A1003(一遍Dijkstra+多重标尺)(AC)

1003 Emergency

分数 25

全屏浏览题目

切换布局

作者 CHEN, Yue

单位 浙江大学

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.

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

代码长度限制

16 KB

时间限制

400 ms

内存限制

64 MB


代码:

import java.util.Scanner;

/**
 * 有个问题?
 * 邻接表怎么记录边权?
 * 把边权记录到节点里,节点有两个属性,一个是编号,另一个是边权
 */

/**
 * 保证最短距离的同时获取最大点权
 * 1.建图:无向图,带环,每个节点有权重,有边权--->邻接矩阵,初始化边权为INF
 * 2.常规dijkstra,更新最短路径时更新最大点权--->需要开辟一个数组记录点权,另一个数组记录起点s到每个点的最大点权和
 * 3.点的序号从0开始到n-1
 */
public class PAT_A1003 {

    final static int MAXN=501;
    final static int INF=100000001;
    static int n;//节点个数
    static int m;//边数
    static int c1;//起点
    static int c2;//终点
    static int[] vertexWeight=new int[MAXN];//记录点权
    static int[][] g=new int[MAXN][MAXN];//记录边权

    //Dijkstra:
    static boolean[] vis=new boolean[MAXN];
    static int[] d=new int[MAXN];
    static int[] sumVerWeight=new int[MAXN];//记录最大点权和 //记得初始化
    static int[] shortPaths=new int[MAXN];//记录最短路径条数 //记得初始化

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        n= scanner.nextInt();
        m= scanner.nextInt();
        c1= scanner.nextInt();
        c2= scanner.nextInt();
        for(int i=0;i<n;i++){
            vertexWeight[i]= scanner.nextInt();
        }
        for(int i=0;i<MAXN;i++){
            for(int j=0;j<MAXN;j++){
                g[i][j]=INF;
            }
        }
        for (int i=0;i<m;i++){
            int v1= scanner.nextInt();
            int v2= scanner.nextInt();
            int length= scanner.nextInt();
            g[v1][v2]=length;
            g[v2][v1]=length;//TODO 他妈的无向图这里不要忘了
        }

        //以上建图完毕
        /**
         * 则通过Dijkstra求出最短路径个数、求出最短路径时的最大点权
         */
        dijkstra(c1);
        System.out.print(shortPaths[c2]+" ");
        System.out.print(sumVerWeight[c2]);
    }

    public static void dijkstra(int start){
        //Dijkstra初始化操作
        for(int i=0;i<MAXN;i++){
            d[i]=INF;
        }
        d[start]=0;
        for(int i=0;i<MAXN;i++){
            sumVerWeight[i]=0;
            shortPaths[i]=0;
        }
        sumVerWeight[start]=vertexWeight[start];
        shortPaths[start]=1;

        //初始化完成
        for (int i=0;i<n;i++){
            int u=-1;
            int MIN=INF;
            for(int j=0;j<n;j++){
                if(vis[j]==false&&d[j]<MIN){
                    u=j;
                    MIN=d[j];
                }
            }
            if(u==-1) return;
            vis[u]=true;
            for(int v=0;v<n;v++){
                if(vis[v]==false&&g[u][v]!=INF){
                    if(d[u]+g[u][v]<d[v]){
                        d[v]=d[u]+g[u][v];
                        shortPaths[v]=shortPaths[u];//TODO 记得更新最短路径条数
                        sumVerWeight[v]=sumVerWeight[u]+vertexWeight[v];//TODO 记得更新点权和
                    }else if((d[u]+g[u][v]==d[v])){//TODO 当d[u]+g[u][v]==d[v]时,无论是否sumVerWeight[u]+vertexWeight[v]>sumVerWeight[v],都应当让shortPaths[v]+=shortPaths[u],因为最短路径条数
                                                       //TODO     的依据仅仅是第一标尺的距离,与点权无关
                        shortPaths[v]+=shortPaths[u];
                        if(sumVerWeight[u]+vertexWeight[v]>sumVerWeight[v]){
                            sumVerWeight[v]=sumVerWeight[u]+vertexWeight[v];
                        }
                    }
                }
            }
        }
    }
}

PAT A1018(Dijkstra+dfs+多重标尺)(AC)

1018 Public Bike Management

分数 30

全屏浏览题目

切换布局

作者 CHEN, Yue

单位 浙江大学

There is a public bike service in Hangzhou City which provides great convenience to the tourists from all over the world. One may rent a bike at any station and return it to any other stations in the city.

The Public Bike Management Center (PBMC) keeps monitoring the real-time capacity of all the stations. A station is said to be in perfect condition if it is exactly half-full. If a station is full or empty, PBMC will collect or send bikes to adjust the condition of that station to perfect. And more, all the stations on the way will be adjusted as well.

When a problem station is reported, PBMC will always choose the shortest path to reach that station. If there are more than one shortest path, the one that requires the least number of bikes sent from PBMC will be chosen.

image.png

The above figure illustrates an example. The stations are represented by vertices and the roads correspond to the edges. The number on an edge is the time taken to reach one end station from another. The number written inside a vertex S is the current number of bikes stored at S. Given that the maximum capacity of each station is 10. To solve the problem at S3​, we have 2 different shortest paths:

  1. PBMC -> S1​ -> S3​. In this case, 4 bikes must be sent from PBMC, because we can collect 1 bike from S1​ and then take 5 bikes to S3​, so that both stations will be in perfect conditions.
  2. PBMC -> S2​ -> S3​. This path requires the same time as path 1, but only 3 bikes sent from PBMC and hence is the one that will be chosen.

Input Specification:

Each input file contains one test case. For each case, the first line contains 4 numbers: Cmax​ (≤100), always an even number, is the maximum capacity of each station; N (≤500), the total number of stations; Sp​, the index of the problem station (the stations are numbered from 1 to N, and PBMC is represented by the vertex 0); and M, the number of roads. The second line contains N non-negative numbers Ci​ (i=1,⋯,N) where each Ci​ is the current number of bikes at Si​ respectively. Then M lines follow, each contains 3 numbers: Si​, Sj​, and Tij​ which describe the time Tij​ taken to move betwen stations Si​ and Sj​. All the numbers in a line are separated by a space.

Output Specification:

For each test case, print your results in one line. First output the number of bikes that PBMC must send. Then after one space, output the path in the format: 0−>S1​−>⋯−>Sp​. Finally after another space, output the number of bikes that we must take back to PBMC after the condition of Sp​ is adjusted to perfect.

Note that if such a path is not unique, output the one that requires minimum number of bikes that we must take back to PBMC. The judge's data guarantee that such a path is unique.

Sample Input:

10 3 3 5
6 7 0
0 1 1
0 2 1
0 3 3
1 3 1
2 3 1

Sample Output:

3 0->2->3 0

代码长度限制

16 KB

时间限制

400 ms

内存限制

64 MB

代码:

package 最短路径;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Vector;

/**
 * 题目分析:
 * 1.PBMC为一个节点,标号为0,为起点
 * 2.其余节点标号从1到n
 * 3.题目给定一个问题节点标号Sp
 * 4.二重标尺: 最短距离 涉及点权(从PBMC派出最少的自行车使得路径上每个节点的权重都为最大权重的一半)
 * //TODO 其实仔细读题,最后结果是依赖三重标尺的:1.最短距离 2.最小need 3.最短距离与最小need相同的路径有多条时,取决于最小back
 *
 * 思路:
 * 1.邻接矩阵建图,记录点权
 * 2.dijkstra记录下所有最短路径
 * 3.dfs这些最短路径,获取optNeed
 */
public class PAT_A1018 {

    final static int INF=10000001;
    final static int MAXN=510;
    static int CMAX;//最大权重
    static int halfCMAX;//最大权重一半
    static int N;//节点个数
    static int SP;//终点的序号
    static int M;//总边数
    static int[][] g=new int[MAXN][MAXN];
    static int[] verWeight=new int[MAXN];//点权

    //dijkstra:
    static int[] d=new int[MAXN];
    static boolean[] vis=new boolean[MAXN];
    static Vector<Integer>[] pres=new Vector[MAXN];

    //dfs:
    static Vector<Integer> optPath=new Vector<>();
    static Vector<Integer> tempPath=new Vector<>();
    static int optNeed=INF;//记录要从起点运出多少车
    static int optBack=INF;//记录要运多少车回起点

    public static void main(String[] args) throws IOException {
        //输入
        InputStreamReader ir = new InputStreamReader(System.in);
        BufferedReader br = new BufferedReader(ir);
        String line = br.readLine();
        String[] s = line.split(" ");
        CMAX=Integer.parseInt(s[0]);
        halfCMAX=CMAX/2;
        N=Integer.parseInt(s[1]);
        SP=Integer.parseInt(s[2]);
        M=Integer.parseInt(s[3]);
        String line1 = br.readLine();
        String[] s1 = line1.split(" ");
        for(int i=0;i<N;i++){
            verWeight[i+1]=Integer.parseInt(s1[i])-halfCMAX;//节点序号从1开始 //TODO 我们保存的权重不是题目直接给的权重,而是处理后的权重--->对后续求第二标尺有帮助
                                                                            //TODO 如果处理后的权重大于0,说明该节点的车可往后运(back);小于0则说明该节点需要前面节点(包括起点)的车(need)
        }
        for(int i=0;i<MAXN;i++){
            for(int j=0;j<MAXN;j++){
                g[i][j]=INF;
            }
        }
        for(int i=0;i<M;i++){
            String line2 = br.readLine();
            String[] s2 = line2.split(" ");
            int v1=Integer.parseInt(s2[0]);
            int v2=Integer.parseInt(s2[1]);
            int dis=Integer.parseInt(s2[2]);
            g[v1][v2]=dis;
            g[v2][v1]=dis;
        }
        //输入完毕

        //dijkstra记录下最短路径:
        dijkstra(0);
        //dfs来求得最优路径以及最优解
        dfs(SP);
        System.out.print(optNeed+" ");
        for(int i=optPath.size()-1;i>=0;i--){
            if(i==0){
                System.out.print(optPath.get(0)+" ");
            }else{
                System.out.print(optPath.get(i)+"->");
            }
        }
        System.out.print(optBack);
    }

    public static void dfs(int v){
        if(v==0){
            tempPath.add(v);
            int tempNeed=0;
            int tempBack=0;
            //TODO 逆序遍历tempPath求出tempNeed与tempBack并更新optNeed与optBack
            //TODO 求tempNeed与tempBack的方法就是模拟+动态更新
            for(int i=tempPath.size()-1;i>=0;i--){//逆序访问tempPath实际上是正序访问路径
                int id=tempPath.get(i);
                if(verWeight[id]>0){
                    tempBack+=verWeight[id];
                }else{
                    if(tempBack > (0-verWeight[id])){
                        tempBack+=verWeight[id];
                    }else{
                        tempNeed+=0-(tempBack+verWeight[id]);
                        tempBack=0;
                    }
                }
            }
            if(tempNeed<optNeed){
                optNeed=tempNeed;
                optBack=tempBack;
                optPath.clear();
                for (Integer integer : tempPath) {
                    optPath.add(integer);
                }
            }else if(tempNeed==optNeed&&tempBack<optBack){//TODO 此时满足:最短路径+最小need,题目说如果有多种这样情况时,再根据最小back判优,保证答案的唯一性
                optBack=tempBack;
                optPath.clear();
                for (Integer integer : tempPath) {
                    optPath.add(integer);
                }
            }
            tempPath.remove((Object)v);
            return;
        }
        tempPath.add(v);
        for(int i=0;i<pres[v].size();i++){
            dfs(pres[v].get(i));
        }
        tempPath.remove((Object)v);
    }

    public static void falseDfs(int des){//TODO 最开始写的错误的dfs,主要是最优解求错了
        if(des==0){
            tempPath.add(des);
            int tempValue=0;
            for(int i=0;i<tempPath.size();i++){//TODO 这里对最优解的求解方式是错误的,因为后面站点的车不能往前面运 从95行到118行
                                                //TODO 属于想都没想清楚就偷懒认为理所当然
                tempValue+=verWeight[tempPath.get(i)];
            }
            tempValue=halfCMAX*(tempPath.size()-1)-tempValue;
            if(tempValue>0){//没有车需要运回起点
                optBack=0;
                if(tempValue<optNeed){
                    optNeed=tempValue;
                    optPath.clear();
                    for (Integer integer : tempPath) {
                        optPath.add(integer);
                    }
                }
            }else{//没有车需要从起点运出
                tempValue=-tempValue;
                optNeed=0;
                if(tempValue<optBack){
                    optBack=tempValue;
                    optPath.clear();
                    for (Integer integer : tempPath) {
                        optPath.add(integer);
                    }
                }
            }
            tempPath.remove((Object)des);
            return;//TODO 不要忘记了,否则会导致StackOverflowError
        }
        tempPath.add(des);
        for(int i=0;i<pres[des].size();i++){
            dfs(pres[des].get(i));
        }
        tempPath.remove((Object)des);
    }

    public static void dijkstra(int begin){
        //初始化
        for(int i=0;i<MAXN;i++){
            d[i]=INF;
            pres[i]=new Vector<>();
        }
        d[begin]=0;

        for(int i=0;i<N+1;i++){//有N+1个节点
            int u=-1;
            int MIN=INF;
            for(int j=0;j<N+1;j++){
                if(vis[j]==false&&d[j]<MIN){
                    u=j;
                    MIN=d[j];
                }
            }
            if(u==-1) return;
            vis[u]=true;
            for(int v=0;v<N+1;v++){
                if(vis[v]==false&&g[u][v]!=INF){
                    if(d[u]+g[u][v]<d[v]){
                        d[v]=d[u]+g[u][v];
                        pres[v].clear();
                        pres[v].add(u);
                    }else if(d[u]+g[u][v]==d[v]){
                        pres[v].add(u);
                    }
                }
            }
        }
    }
}

PAT A1030(Dijkstra+dfs+多重标尺)(AC)

1030 Travel Plan

分数 30

全屏浏览题目

切换布局

作者 CHEN, Yue

单位 浙江大学

A traveler's map gives the distances between cities along the highways, together with the cost of each highway. Now you are supposed to write a program to help a traveler to decide the shortest path between his/her starting city and the destination. If such a shortest path is not unique, you are supposed to output the one with the minimum cost, which is guaranteed to be unique.

Input Specification:

Each input file contains one test case. Each case starts with a line containing 4 positive integers N, M, S, and D, where N (≤500) is the number of cities (and hence the cities are numbered from 0 to N−1); M is the number of highways; S and D are the starting and the destination cities, respectively. Then M lines follow, each provides the information of a highway, in the format:

City1 City2 Distance Cost

where the numbers are all integers no more than 500, and are separated by a space.

Output Specification:

For each test case, print in one line the cities along the shortest path from the starting point to the destination, followed by the total distance and the total cost of the path. The numbers must be separated by a space and there must be no extra space at the end of output.

Sample Input:

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

Sample Output:

0 2 3 3 40

代码长度限制

16 KB

时间限制

400 ms

内存限制

64 MB

代码:

import java.util.Scanner;
import java.util.Vector;

/**
 * 1.双重标尺:最短路径+最小边权
 * 2.顶点序号0~n-1
 * 3.求双重标尺下的路径+距离+边权
 * 4.无向图
 *
 * 求解:
 * 1.邻接矩阵记录距离
 * 2.开二维数组记录边权
 * 3.dijkstra+dfs
 */
public class PAT_A1030 {

    static int n;//节点个数
    static int m;//边个数
    static int s;
    static int d;
    final static int MAXN=510;
    final static int INF=10000001;
    static int[][] g=new int[MAXN][MAXN];//距离
    static int[][] edgeWeight=new int[MAXN][MAXN];//边权

    //dijkstra:
    static int[] dis=new int[MAXN];
    static boolean[] vis=new boolean[MAXN];
    static Vector<Integer>[] pre=new Vector[MAXN];

    //dfs:
    static Vector<Integer> tempPath=new Vector<>();
    static Vector<Integer> optPath=new Vector<>();
    static int optValue=INF;

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        n= scanner.nextInt();
        m= scanner.nextInt();
        s= scanner.nextInt();
        d= scanner.nextInt();
        for(int i=0;i<MAXN;i++){
            for(int j=0;j<MAXN;j++){
                g[i][j]=INF;
                edgeWeight[i][j]=INF;
            }
        }
        for(int i=0;i<m;i++){
            int v1= scanner.nextInt();
            int v2= scanner.nextInt();
            int distance= scanner.nextInt();
            int weight= scanner.nextInt();
            g[v1][v2]=distance;
            g[v2][v1]=distance;
            edgeWeight[v1][v2]=weight;
            edgeWeight[v2][v1]=weight;
        }
        //图初始化完毕
        //Dijkstra记录下所有最短路径:
        dijkstra(s);
        //dfs遍历所有最短路径,筛选出边权最小的:
        dfs(d);
        //输出结果:
        for(int i=optPath.size()-1;i>=0;i--){
            System.out.print(optPath.get(i)+" ");
        }
        System.out.print(dis[d]+" ");
        System.out.print(optValue);
    }

    public static void dfs(int des){
        if(des==s){
            tempPath.add(des);
            int tempValue=0;
            for (int i=0;i< tempPath.size()-1;i++){
                int v1 = tempPath.get(i);
                int v2 = tempPath.get(i+1);
                tempValue+=edgeWeight[v1][v2];
            }
            if(tempValue<optValue){
                optValue=tempValue;
                optPath.clear();
                for (Integer integer : tempPath) {//深拷贝
                    optPath.add(integer);
                }
            }
            tempPath.remove((Object)des);//TODO 这里不强制类型转换的话,集合会默认是按index删除元素
            return;
        }
        tempPath.add(des);
        for(int i=0;i<pre[des].size();i++){
            dfs(pre[des].get(i));
        }
        tempPath.remove((Object)des);
    }

    public static void dijkstra(int start){
        //dijkstra初始化
        for(int i=0;i<MAXN;i++){
            dis[i]=INF;
            pre[i]=new Vector<>();
        }
        dis[start]=0;

        for(int i=0;i<n;i++){
            int u=-1;
            int MIN=INF;
            for(int j=0;j<n;j++){
                if(vis[j]==false&&dis[j]<MIN) {
                    u = j;
                    MIN = dis[j];
                }
            }
            if(u==-1) return;
            vis[u]=true;
            for(int v=0;v<n;v++){
                if(vis[v]==false&&g[u][v]!=INF){
                    if(dis[u]+g[u][v]<dis[v]){
                        dis[v]=dis[u]+g[u][v];
                        pre[v].clear();//一定要记得clear掉
                        pre[v].add(u);
                    }else if(dis[u]+g[u][v]==dis[v]){
                        pre[v].add(u);
                    }
                }
            }
        }
    }
}

PAT A1072(多次Dijkstra+灵活利用d[])(26,超时)

1072 Gas Station

分数 30

全屏浏览题目

切换布局

作者 CHEN, Yue

单位 浙江大学

A gas station has to be built at such a location that the minimum distance between the station and any of the residential housing is as far away as possible. However it must guarantee that all the houses are in its service range.

Now given the map of the city and several candidate locations for the gas station, you are supposed to give the best recommendation. If there are more than one solution, output the one with the smallest average distance to all the houses. If such a solution is still not unique, output the one with the smallest index number.

Input Specification:

Each input file contains one test case. For each case, the first line contains 4 positive integers: N (≤103), the total number of houses; M (≤10), the total number of the candidate locations for the gas stations; K (≤104), the number of roads connecting the houses and the gas stations; and DS​, the maximum service range of the gas station. It is hence assumed that all the houses are numbered from 1 to N, and all the candidate locations are numbered from G1 to GM.

Then K lines follow, each describes a road in the format

P1 P2 Dist

where P1 and P2 are the two ends of a road which can be either house numbers or gas station numbers, and Dist is the integer length of the road.

Output Specification:

For each test case, print in the first line the index number of the best location. In the next line, print the minimum and the average distances between the solution and all the houses. The numbers in a line must be separated by a space and be accurate up to 1 decimal place. If the solution does not exist, simply output No Solution.

Sample Input 1:

4 3 11 5
1 2 2
1 4 2
1 G1 4
1 G2 3
2 3 2
2 G2 1
3 4 2
3 G3 2
4 G1 3
G2 G1 1
G3 G2 2

Sample Output 1:

G1
2.0 3.3

Sample Input 2:

2 1 2 10
1 G1 9
2 G1 20

Sample Output 2:

No Solution

代码长度限制

16 KB

时间限制

200 ms

内存限制

64 MB

代码:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

/**
 * 题目分析:
 * 1.两类节点:汽油站、居民点
 * 2.汽油站是起点,从起点开始要能访问到所有的居民点
 * 3.四个要求:1.从起点开始要能访问到所有的居民点 2.首先选择距离各个居民点最短距离最大的站点 3.如果有多个则smallest average,而居民点个数相同,便是要求到达各居民点的最短路径总和 4.如果满足1. 2.的路径有多条,那么选取汽油站编号最小的那个
 * 4.输出:No Solution/选取的汽油站+选取的汽油站到居民点的最小距离+平均距离
 * 5.居民编号由1到n,汽油站编号由g1到gm
 *
 * 思路:
 * 1.一个一个汽油站解决  有个问题:当解决当前汽油站的时候,其他汽油站也是在图中的,怎么表示?--->居民范围是[1,n],那不如把汽油站映射到n以后
 * 2.对于每个汽油站:dijkstra得到d[],如果所有d[]都小于汽油站服务范围,则满足要求1.,并累加d[]得到当前最短路径总和,如果当前最短路径总和小于或等于最短路径总和,则需要记录下汽油站编号+最小的d[]+最短路径总和
 * 3.遍历2.记录下的,得出结果
 *
 */
public class PAT_A1072 {

    final static int MAXN=1050;
    final static int INF=10000001;
    static int N;//居民点个数
    static int M;//候选汽油站个数
    static int K;//边数
    static int D;//汽油站最大服务距离
    static int[][]g=new int[MAXN][MAXN];
    static HashMap<String,Integer> stationToInt=new HashMap<>();
    static HashMap<Integer,String> intToStation=new HashMap<>();

    //dijkstra:
    static int[] d=new int[MAXN];
    static boolean[] vis=new boolean[MAXN];
    static int maxDistance=0;//维持各个站点距离其最近的村庄的最大距离
    static int shortPath=INF;//记录最短路径总和
    static int minIndex=-1;//记录站点序号

    public static void main(String[] args) throws IOException {
        InputStreamReader ir = new InputStreamReader(System.in);
        BufferedReader br = new BufferedReader(ir);
        String line = br.readLine();
        String[] s = line.split(" ");
        N= Integer.parseInt(s[0]);
        M= Integer.parseInt(s[1]);
        K= Integer.parseInt(s[2]);
        D= Integer.parseInt(s[3]);
        for(int i=0;i<MAXN;i++){
            for(int j=0;j<MAXN;j++){
                g[i][j]=INF;
            }
        }
        for(int i=0;i<K;i++){
            String line1 = br.readLine();
            String[] s1 = line1.split(" ");
            String v1= s1[0];
            String v2= s1[1];
            int ver1=0;
            int ver2=0;
            if(v1.charAt(0)!='G'){
                ver1=Integer.parseInt(v1);
            }else{
                ver1=change(v1);
            }
            if(v2.charAt(0)!='G'){
                ver2=Integer.parseInt(v2);
            }else{
                ver2=change(v2);
            }
            int dis= Integer.parseInt(s1[2]);
            g[ver1][ver2]=dis;
            g[ver2][ver1]=dis;
        }
        br.close();
        //分别对每个汽油站dijkstra:

        HashMap<String, Integer> hp = new HashMap<String, Integer>();//key:汽油站编号 value:最小的d[](并且要是居民点)
        for(int i=N+1;i<=N+M;i++){//TODO 本来就是按汽油站序号遍历的,所以第一个记录的永远是index最小的汽油站,不需要集合存储满足条件的多个汽油站
            boolean tempFlag=true;
            int tempMin=INF;
            int tempPath=0;
            for(int j=0;j<MAXN;j++){//TODO 因为要用多次dijkstra,所以要消除上一次使用的影响
                vis[j]=false;
            }
            dijkstra(i);
            for(int j=1;j<=N;j++){
                if(d[j]>D){
                    tempFlag=false;
                    break;
                }
            }
            if(tempFlag==true){//所有居民点都在范围内
                for(int j=1;j<=N;j++){
                    if(d[j]<tempMin){
                        tempMin=d[j];
                    }
                    tempPath+=d[j];
                }
                if(tempMin>maxDistance){//TODO 题目要求的是:选取各个站点距离居民点的最短距离的最大值对应的站点
                    minIndex=i;
                    maxDistance=tempMin;
                    shortPath=tempPath;
                }else if(tempMin==maxDistance&&tempPath<shortPath){
                    minIndex=i;
                    shortPath=tempPath;
                }
            }
        }
        if(minIndex==-1){
            System.out.print("No Solution");
        }else{
            System.out.println(intToStation.get(minIndex));
            System.out.printf("%.1f %.1f",1.0*maxDistance,1.0*shortPath/N);
        }
    }

    public static void dijkstra(int start){
        for(int i=0;i<MAXN;i++){
            d[i]=INF;
        }
        d[start]=0;
        for(int i=0;i<N+M;i++){
            int u=-1;
            int MIN=INF;
            for(int j=1;j<=N+M;j++){
                if(vis[j]==false&&d[j]<MIN){
                    u=j;
                    MIN=d[j];
                }
            }
            if(u==-1) return;
            vis[u]=true;
            for(int v=1;v<=N+M;v++){
                if(vis[v]==false&&g[u][v]!=INF){
                    if(d[u]+g[u][v]<d[v]){
                        d[v]=d[u]+g[u][v];
                    }
                }
            }
        }
    }

    public static int change(String station){
        if(stationToInt.containsKey(station)){
            return stationToInt.get(station);
        }else{
            int num=0;
            if(station.length()==3){//处理G10
                num=10;
            }else{
                char c = station.charAt(1);
                String s=""+c;
                num=Integer.parseInt(s);
            }
            stationToInt.put(station,num+N);
            intToStation.put(num+N,station);
            return num+N;
        }
    }
}

PAT A1087(Dijkstra+dfs+多重标尺)(AC)

1087 All Roads Lead to Rome

分数 30

全屏浏览题目

切换布局

作者 CHEN, Yue

单位 浙江大学

Indeed there are many different tourist routes from our city to Rome. You are supposed to find your clients the route with the least cost while gaining the most happiness.

Input Specification:

Each input file contains one test case. For each case, the first line contains 2 positive integers N (2≤N≤200), the number of cities, and K, the total number of routes between pairs of cities; followed by the name of the starting city. The next N−1 lines each gives the name of a city and an integer that represents the happiness one can gain from that city, except the starting city. Then K lines follow, each describes a route between two cities in the format City1 City2 Cost. Here the name of a city is a string of 3 capital English letters, and the destination is always ROM which represents Rome.

Output Specification:

For each test case, we are supposed to find the route with the least cost. If such a route is not unique, the one with the maximum happiness will be recommanded. If such a route is still not unique, then we output the one with the maximum average happiness -- it is guaranteed by the judge that such a solution exists and is unique.

Hence in the first line of output, you must print 4 numbers: the number of different routes with the least cost, the cost, the happiness, and the average happiness (take the integer part only) of the recommanded route. Then in the next line, you are supposed to print the route in the format City1->City2->...->ROM.

Sample Input:

6 7 HZH
ROM 100
PKN 40
GDN 55
PRS 95
BLN 80
ROM GDN 1
BLN ROM 1
HZH PKN 1
PRS ROM 2
BLN HZH 2
PKN GDN 1
HZH PRS 1

Sample Output:

3 3 195 97
HZH->PRS->ROM

代码长度限制

16 KB

时间限制

200 ms

内存限制

64 MB

代码:

import java.util.HashMap;
import java.util.Scanner;
import java.util.Vector;

/**
 * 题目分析:
 * 1.告诉起点,告诉终点,边权为cost,点权为happiness
 * 2.要求:最短路径条数 最小边权  最短路径有多条时--->最大点权   最大点权有多条--->最大点权平均值
 *
 * 思路:
 * 1.建立城市名字String与序号int的双向映射
 * 2.构建无向图,邻接矩阵存储边权
 * 3.dijkstra记录下所有最短路径
 * 4.dfs
 */
public class PAT_A1087 {

    final static int MAXN=210;
    final static int INF=10000001;
    static int n;//节点个数
    static int k;//边的个数
    static int start;//起点
    static HashMap<String,Integer> stringtoInt=new HashMap<>();
    static HashMap<Integer,String> intToString=new HashMap<>();
    static int currentVertexes=0;//节点序号从0开始
    static int[] weight=new int[MAXN];//点权
    static int[][] g=new int[MAXN][MAXN];

    //dijkstra:
    static int[] d=new int[MAXN];
    static boolean[] vis=new boolean[MAXN];
    static Vector<Integer>[] pres=new Vector[MAXN];

    //dfs:
    static Vector<Integer> tempPath=new Vector<>();
    static Vector<Integer> optPath=new Vector<>();
    static int maxSumvertex=0;
    static int maxSumvertexAvg=0;
    static int shortPaths=0;

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        n= scanner.nextInt();
        k= scanner.nextInt();
        String s= scanner.next();
        start=change(s);
        weight[start]=0;
        for(int i=0;i<n-1;i++){
            String s1= scanner.next();
            int wei= scanner.nextInt();
            int v1 = change(s1);
            weight[v1]=wei;
        }
        for(int i=0;i<MAXN;i++){
            for(int j=0;j<MAXN;j++){
                g[i][j]=INF;//TODO 他妈的!!!用邻接矩阵存储图的时候不要他妈的忘记了给所有边权初始化为INF他妈的
            }
        }
        for(int i=0;i<k;i++){
            String s1= scanner.next();
            String s2= scanner.next();
            int dis= scanner.nextInt();
            int v1 = change(s1);
            int v2 = change(s2);
            g[v1][v2]=dis;
            g[v2][v1]=dis;
        }

        //dijkstra记录最短路径
        dijkstra(start);
        //dfs
        dfs(stringtoInt.get("ROM"));

        System.out.println(shortPaths+" "+d[stringtoInt.get("ROM")]+" "+maxSumvertex+" "+maxSumvertexAvg);
        for(int i= optPath.size()-1;i>=0;i--){
            if(i==0){
                System.out.print(intToString.get(optPath.get(i)));
            }else{
                System.out.print(intToString.get(optPath.get(i))+"->");
            }
        }

    }

    public static void dfs(int v){
        if(v==start){
            shortPaths++;
            int tempMaxSumVertex=0;
            int tempMaxSumVertexAVG=0;
            tempPath.add(v);
            for(int i=0;i<tempPath.size();i++){
                tempMaxSumVertex+=weight[tempPath.get(i)];
            }
            tempMaxSumVertexAVG=tempMaxSumVertex/(tempPath.size()-1);
            if(tempMaxSumVertex>maxSumvertex){
                maxSumvertex=tempMaxSumVertex;
                maxSumvertexAvg=tempMaxSumVertexAVG;//TODO 不要  只   记得更新maxSumvertex=tempMaxSumVertex  ,这个他妈的也要记得更新!!!!!!!!!因为tempMaxSumVertex>maxSumvertex的优先级更高,已经换情况了
                                                                            //TODO 因为他妈的maxSumvertexAvg是他妈的次标尺,主标尺更新了,其他的次标尺他妈的一定也要记得随着主标尺更新,不要忘记了
                optPath.clear();
                for (Integer integer : tempPath) {
                    optPath.add(integer);
                }
            }else if(tempMaxSumVertex==maxSumvertex&&tempMaxSumVertexAVG>maxSumvertexAvg){
                maxSumvertexAvg=tempMaxSumVertexAVG;
                optPath.clear();
                for (Integer integer : tempPath) {
                    optPath.add(integer);
                }
            }
            tempPath.remove((Object)v);
            return;
        }
        tempPath.add(v);
        for (Integer integer : pres[v]) {
            dfs(integer);
        }
        tempPath.remove((Object)v);
    }

    public static void dijkstra(int s){
        for(int i=0;i<MAXN;i++){
            d[i]=INF;
            pres[i]=new Vector<>();
        }
        d[s]=0;
        for(int i=0;i<n;i++){
            int u=-1;
            int MIN=INF;
            for(int j=0;j<n;j++){
                if(vis[j]==false&&d[j]<MIN){
                    u=j;
                    MIN=d[j];
                }
            }
            if(u==-1) return;
            vis[u]=true;
            for(int v=0;v<n;v++){
                if(vis[v]==false&&g[u][v]!=INF){
                    if(d[u]+g[u][v]<d[v]){
                        d[v]=d[u]+g[u][v];
                        pres[v].clear();
                        pres[v].add(u);
                    }else if(d[u]+g[u][v]==d[v]){
                        pres[v].add(u);
                    }
                }
            }
        }
    }

    public static int change(String s){
        if(stringtoInt.keySet().contains(s)){
            return stringtoInt.get(s);
        }else{
            int num=currentVertexes;
            stringtoInt.put(s,num);
            intToString.put(num,s);
            return currentVertexes++;
        }
    }
}

PAT A1111(两次dijkstra的同时维护最优解)(27,超时)

1111 Online Map

分数 30

全屏浏览题目

切换布局

作者 CHEN, Yue

单位 浙江大学

Input our current position and a destination, an online map can recommend several paths. Now your job is to recommend two paths to your user: one is the shortest, and the other is the fastest. It is guaranteed that a path exists for any request.

Input Specification:

Each input file contains one test case. For each case, the first line gives two positive integers N (2≤N≤500), and M, being the total number of streets intersections on a map, and the number of streets, respectively. Then M lines follow, each describes a street in the format:

V1 V2 one-way length time

where V1 and V2 are the indices (from 0 to N−1) of the two ends of the street; one-way is 1 if the street is one-way from V1 to V2, or 0 if not; length is the length of the street; and time is the time taken to pass the street.

Finally a pair of source and destination is given.

Output Specification:

For each case, first print the shortest path from the source to the destination with distance D in the format:

Distance = D: source -> v1 -> ... -> destination

Then in the next line print the fastest path with total time T:

Time = T: source -> w1 -> ... -> destination

In case the shortest path is not unique, output the fastest one among the shortest paths, which is guaranteed to be unique. In case the fastest path is not unique, output the one that passes through the fewest intersections, which is guaranteed to be unique.

In case the shortest and the fastest paths are identical, print them in one line in the format:

Distance = D; Time = T: source -> u1 -> ... -> destination

Sample Input 1:

10 15
0 1 0 1 1
8 0 0 1 1
4 8 1 1 1
3 4 0 3 2
3 9 1 4 1
0 6 0 1 1
7 5 1 2 1
8 5 1 2 1
2 3 0 2 2
2 1 1 1 1
1 3 0 3 1
1 4 0 1 1
9 7 1 3 1
5 1 0 5 2
6 5 1 1 2
3 5

Sample Output 1:

Distance = 6: 3 -> 4 -> 8 -> 5
Time = 3: 3 -> 1 -> 5

Sample Input 2:

7 9
0 4 1 1 1
1 6 1 1 3
2 6 1 1 1
2 5 1 2 2
3 0 0 1 1
3 1 1 1 3
3 2 1 1 2
4 5 0 2 2
6 5 1 1 2
3 5

Sample Output 2:

Distance = 3; Time = 4: 3 -> 2 -> 5

代码长度限制

16 KB

时间限制

400 ms

内存限制

64 MB

代码:

import java.util.Scanner;
import java.util.Vector;

/**
 * 题目分析:
 * 1.有向图(one-way),标志1表示单向,标志0表示双向
 * 2.顶点序号从0到n-1
 * 3.找最短路径--->最短路径不唯一的时候,看最短时间
 * 4.找最短时间--->最短时间不唯一的时候,看经过的最少节点
 * 5.最短时间不一定是在最短路径中产生
 *
 * 思路:
 * 1.两次dijkstra,一次把路径作为边权,一次把时间作为边权
 * 2.还是得用dijkstra+dfs
 */
public class PAT_A1111 {

    final static int MAXN=510;
    final static int INF=1000001;
    static int n;//节点数
    static int m;//边数
    static int start;
    static int des;
    static int[][] g=new int[MAXN][MAXN];//记录距离
    static int[][] time=new int[MAXN][MAXN];//记录时间

    //dijkstra:
    static int[] d=new int[MAXN];
    static boolean[] vis=new boolean[MAXN];
    static Vector<Integer>[] pres=new Vector[MAXN];

    //dfs:
    static Vector<Integer> tempPath= new Vector<>();
    static Vector<Integer> optPath= new Vector<>();//记录最短路径
    static int shortTime=INF;//最短路径下的最短时间
    static int shortDistance=0;
    //dfs2:
    static Vector<Integer> tempPath2=new Vector<>();
    static Vector<Integer> optPath2=new Vector<>();//记录最短时间
    static int leastVertex=INF;//路径上最少节点数
    static int sTime=0;


    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        n= scanner.nextInt();
        m= scanner.nextInt();
        for(int i=0;i<MAXN;i++){
            for(int j=0;j<MAXN;j++){
                g[i][j]=INF;
                time[i][j]=INF;
            }
        }
        for (int i=0;i<m;i++){
            int v1= scanner.nextInt();
            int v2= scanner.nextInt();
            int isOneWay= scanner.nextInt();//1则是单向,0则是双向
            int tempLength= scanner.nextInt();
            int tempTime= scanner.nextInt();
            g[v1][v2]=tempLength;
            time[v1][v2]= tempTime;
            if(isOneWay!=1){//双向
                g[v2][v1]=tempLength;
                time[v2][v1]= tempTime;
            }
        }
        start= scanner.nextInt();
        des= scanner.nextInt();
        dijkstra(start);
        dfs(des);
        for(int i=0;i<MAXN;i++){
            vis[i]=false;
        }
        shortDistance=d[des];
        //将边权由距离换成时间
        for(int i=0;i<MAXN;i++){
            for(int j=0;j<MAXN;j++){
                g[i][j]=time[i][j];
            }
        }
        dijkstra(start);
        dfs2(des);
        sTime=d[des];
        boolean flag=true;
        if(optPath.size()==optPath2.size()){
            for(int i=0;i<optPath.size();i++){
                if(optPath.get(i)!=optPath2.get(i)){
                    flag=false;
                    break;
                }
            }
        }else {
            flag=false;
        }

        if(flag){
            System.out.print("Distance"+" = "+shortDistance+"; ");
            System.out.print("Time"+" = "+sTime+": ");
            for(int i=optPath.size()-1;i>=0;i--){
                if(i==0){
                    System.out.print(optPath.get(i));
                }else{
                    System.out.print(optPath.get(i)+" -> ");
                }
            }
        }else{
            System.out.print("Distance"+" = "+shortDistance+": ");
            for(int i=optPath.size()-1;i>=0;i--){
                if(i==0){
                    System.out.println(optPath.get(i));
                }else{
                    System.out.print(optPath.get(i)+" -> ");
                }
            }
            System.out.print("Time"+" = "+sTime+": ");
            for(int i=optPath2.size()-1;i>=0;i--){
                if(i==0){
                    System.out.print(optPath2.get(i));
                }else{
                    System.out.print(optPath2.get(i)+" -> ");
                }
            }
        }
    }

    public static void dfs2(int v){
        if(v==start){
            tempPath2.add(v);
            if(tempPath2.size()<leastVertex){
                leastVertex=tempPath2.size();
                optPath2.clear();
                for (Integer integer : tempPath2) {
                    optPath2.add(integer);
                }
            }
            tempPath2.remove((Object)v);
        }
        tempPath2.add(v);
        for(int i=0;i<pres[v].size();i++){
            dfs2(pres[v].get(i));
        }
        tempPath2.remove((Object)v);
    }

    public static void dfs(int v){
        if(v==start){
            tempPath.add(v);
            int tempTime=0;
            for(int i=tempPath.size()-1;i>=1;i--){
                tempTime+=time[tempPath.get(i)][tempPath.get(i-1)];
            }
            if(tempTime<shortTime){
                shortTime=tempTime;
                optPath.clear();
                for (Integer integer : tempPath) {
                    optPath.add(integer);
                }
            }
            tempPath.remove((Object)v);
            return;
        }
        tempPath.add(v);
        for(int i=0;i<pres[v].size();i++){
            dfs(pres[v].get(i));
        }
        tempPath.remove((Object)v);
    }

    public static void dijkstra(int start){
        for(int i=0;i<MAXN;i++){
            d[i]=INF;
            pres[i]=new Vector<>();
        }
        d[start]=0;
        for(int i=0;i<n;i++){
            int u=-1;
            int MIN=INF;
            for (int j=0;j<n;j++){
                if(vis[j]==false&&d[j]<MIN){
                    u=j;
                    MIN=d[j];
                }
            }
            if(u==-1) return;
            vis[u]=true;
            for(int v=0;v<n;v++){
                if(vis[v]==false&&g[u][v]!=INF){
                    if(d[u]+g[u][v]<d[v]){
                        d[v]=d[u]+g[u][v];
                        pres[v].clear();
                        pres[v].add(u);
                    }else if(d[u]+g[u][v]==d[v]){
                        pres[v].add(u);
                    }
                }
            }
        }
    }
}