【图论】B_NOI 1997_最优乘车(建图 / 临界矩阵存图)

一、题目描述

H城是一个旅游胜地,每年都有成千上万的人前来观光。

为方便游客,巴士公司在各个旅游景点及宾馆,饭店等地都设置了巴士站并开通了一些单程巴士线路。

每条单程巴士线路从某个巴士站出发,依次途经若干个巴士站,最终到达终点巴士站。

一名旅客最近到H城旅游,他很想去S公园游玩,但如果从他所在的饭店没有一路巴士可以直接到达S公园,则他可能要先乘某一路巴士坐几站,再下来换乘同一站台的另一路巴士, 这样换乘几次后到达S公园。

现在用整数1,2,…N 给H城的所有的巴士站编号,约定这名旅客所在饭店的巴士站编号为1,S公园巴士站的编号为N。

写一个程序,帮助这名旅客寻找一个最优乘车方案,使他在从饭店乘车到S公园的过程中换乘的次数最少。

输入格式

  • 第一行有两个数字M和N,表示开通了M条单程巴士线路,总共有N个车站。
  • 从第二行到第M+1行依次给出了第1条到第M条巴士线路的信息,其中第i+1行给出的是第i条巴士线路的信息,从左至右按运行顺序依次给出了该线路上的所有站号,相邻两个站号之间用一个空格隔开。

输出格式

  • 共一行,如果无法乘巴士从饭店到达S公园,则输出”NO”,否则输出最少换乘次数,换乘次数为0表示不需换车即可到达。

数据范围

  • 1≤M≤100,
    1≤N≤500
输入样例:
3 7
6 7
4 7 3 6
2 1 3 5
输出样例:
2

二、题解

方法一:spfa

注意:这题的输入有点不一样,输入的是 E 串一连串的数,而如果直接用 sc.next() 来读取的话,得到的只有一串连续的数字,所以需要读入字符串然后用 split(" ") 分开。

思路

这题考点是建图,数据可抽象为边权为 1,各车站互联成为错杂交错的路线图。
参考图
每一条线路中的每一个车站两两之间构成了一个边权为 1 的连通块,为什么呢?因为一条线路上的车不需要换乘,那么他们虽然看起来距离不一,但在我们的图中,我们只认为换乘才会使距离 +1,所以这就变成为最短路问题啦…

扫描二维码关注公众号,回复: 10865169 查看本文章

最后的减 dist[V] - 1 是怎么回事呢?因为我们第一次上车是不计入换乘次数内的,但为了方便,我们使边权为 1,V 离 1 的最短距离是 换乘次数 +1

import java.util.*;
import java.math.*;
import java.io.*;
public class Main{
	static Edge[] e;
	static int[] dist, head;
	static boolean[] inq;
	static int tot;
	static int INF = 0x3f3f3f3f;
	static int maxv = 3000 + 50, maxe = 20000 + 50; 
	static class Edge {
        int to, w, next;
        Edge() {}
    } 
	static void addEdge(int u, int v, int w) {
		e[++tot] = new Edge();
		e[tot].to = v;
		e[tot].w = w;
		e[tot].next = head[u];
		head[u] = tot;
	}
	static void spfa(int S) {
		Arrays.fill(dist, INF);
		dist[S] = 0;
		ArrayDeque<Integer> q = new ArrayDeque<>();
		q.add(S);
		inq[S] = true;
		
		while (!q.isEmpty()) {
			int v = q.poll();
			inq[v] = false;
			for (int i = head[v]; i != 0; i = e[i].next) {
				int to = e[i].to, w = e[i].w;
				if (dist[to] > dist[v] + w) {
					dist[to] = dist[v] + w;
					if (inq[to]) 
						continue;
					if (!q.isEmpty() && dist[to] < dist[q.peek()]) {
						q.addFirst(to);
					} else {
						q.add(to);
					}
					inq[to] = true;
				}
			}
		}
	}
    public static void main(String[] args) throws IOException {  
        Scanner sc = new Scanner(new BufferedInputStream(System.in));
        BufferedWriter w = new BufferedWriter(new OutputStreamWriter(System.out));
        
        String[] ss = sc.nextLine().split(" ");
		int E = Integer.parseInt(ss[0]);
		int V = Integer.parseInt(ss[1]);
		dist = new int[maxv];
		e = new Edge[maxe];
		inq = new boolean[maxv];
		head = new int[maxv];
		
		while (E-- > 0) {
		    String[] s = sc.nextLine().split(" ");
		    int[] dig = new int[s.length];
		    for (int i = 0; i < s.length; i++) {
		        dig[i] = Integer.parseInt(s[i]);
		    }
    		for (int i = 0; i < dig.length; i++) {
    			for (int j = i+1; j < dig.length; j++)
    				addEdge(dig[i], dig[j], 1);
    		}
		}
		spfa(1);
		System.out.println(dist[V] == INF ? "NO" : dist[V]-1);
    }
}

复杂度分析

  • 时间复杂度: O ( k E ) O(kE)
  • 空间复杂度: O ( . . . ) O(...)

方法二:临界矩阵存图

void spfa(int S) {
	Arrays.fill(dist, INF);
	dist[S] = 0;
	ArrayDeque<Integer> q = new ArrayDeque<>();
	q.add(S);
	inq[S] = true;
	
	while (!q.isEmpty()) {
		int v = q.poll();
		for (int i = 1; i <= V; i++) {
			if (g[v][i] && dist[i] > dist[v] + 1) {
				dist[i] = dist[v] + 1;
				q.add(i);
				inq[i] = true;
			}
		}
	}
}
发布了691 篇原创文章 · 获赞 151 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/qq_43539599/article/details/105558885