ACM入门题-力扣tusimple-005. 服务器-图论最短路径Go语言

16 篇文章 0 订阅

ACM入门题-力扣tusimple-005. 服务器-图论最短路径Go语言

tusimple-005. 服务器 中等

描述

公司来了一批新的分布式服务器,TuTu 要负责启动他们。

公司的服务器都有一个唯一的不会和其他服务器重复的名字,现在一共有 n 台服务器,这些服务器之间有 m 条数据线连接起来。

如果服务器 x 和 y 之间有一条数据线连接,那么在服务器 x 启动的 t 毫秒后,服务器 y 会自动启动(注意启动是有方向的)。当然如果同时服务器 x 和其他服务器也有数据线连接,而那个服务器在关闭状态,则它也会在相应的时间后自动启动。

现在 TuTu 很好奇,如果他启动了一个服务器 a 那么服务器 b 在多长时间以后会被启动。当然了,好奇的人总是会有很多好奇的点,所以 TuTu 会询问好多个这样的问题。需要注意的是,每一次询问都是独立的。

输入描述:

第一行包含整数 n 和 m (2 <= n <= 1000,1 <= m <= 1000),分别为服务器数量和数据线数量。

接下来的 m 行中,每行包含两个不同的字符串 x[i] 和 y[i] 以及整数 t[i] (1 <= t[i] <= 10^9) ,它们描述一个数据线的连接情况。字符串最多包含 20 个小写字母,表示服务器的名称。保证所有服务器的名称都会至少出现一次。某些服务器对之间可能存在多个数据线连接。

接下来的一行包含整数 q (1 <= q <= 1000),表示询问个数。

接下来的 q 行,每行包含两个不同的字符串 a[i] 和 b[i] ,表示 TuTu 询问启动服务器 a[i] 服务器 b[i] 在多长时间以后会被启动。

输出描述:

输出包含 q 行。每一行独立输出每一次询问所需要花费的时间(以毫秒为单位),如果被询问的服务器 b[i] 永远不能被启动,则输出 INF 。

样例1

输入

3 2
novak goat 1
goat simulator 3
2
novak simulator
simulator goat

输出

4
INF

说明
对于第一个询问,TuTu 启动服务器 novak1 毫秒后,服务器 goat 启动,再经过 3 毫秒后所询问的服务器 simulator 启动。

备注:

对于其中 40% 的数据,保证 1 <= n <= 10
对于其中另外 30% 的数据,保证 1 <= n <= 100

思路

  • 降维打击可以看做是单源最短路径问题
  • 使用多次迪杰斯特拉算法求解
package main

import "fmt"

const MAXN = 1000 + 10
const INF int64 = 0x3f3f3f3f3f3f3f3f

var fwq map[string]int    // 标号
var MAP [MAXN][MAXN]int64 // 邻接矩阵
var n, m int              // 结点数(服务器)和单向边数(连接)

// 迪杰斯特拉算法
func Dijkstra(s /*起始结点编号*/ int) {
	vis := [MAXN]bool{} // 标记是否访问过
	vis[s] = true       // 标记访问
	// 遍历访问每个中间结点
	for i := 0; i < n; i++ {
		u := -1                  // 记录当前未被访问过的最小路径结点
		MIN := INF               // 记录当前未被访问结点的最小路径
		for j := 0; j < n; j++ { // 遍历寻找未被访问过的最小路径结点
			if !vis[j] && MIN > MAP[s][j] {
				u = j           // 更新结点
				MIN = MAP[s][j] // 更新最小路径
			}
		}
		if u == -1 { // 已经遍历完了
			return
		}
		vis[u] = true // 标记已访问
		// 更新相连结点的最小路径
		for j := 0; j < n; j++ {
			if !vis[j] && MAP[u][j] != INF && MAP[s][j] > MAP[s][u]+MAP[u][j] {
				MAP[s][j] = MAP[s][u] + MAP[u][j]
			}
		}
	}
}

func main() {
	fwq = make(map[string]int)
	// 初始化临界矩阵
	for i := 0; i < MAXN; i++ {
		for j := 0; j < MAXN; j++ {
			if i != j {
				MAP[i][j] = INF
			}
		}
	}
	index := 0 // 标号数目
	fmt.Scan(&n, &m)
	for i := 0; i < m; i++ {
		var a, b string
		var time int64
		var x, y int
		fmt.Scan(&a, &b, &time)
		// 记录标号
		if _, ok := fwq[a]; ok {
			x = fwq[a]
		} else {
			x = index
			fwq[a] = index
			index++
		}
		if _, ok := fwq[b]; ok {
			y = fwq[b]
		} else {
			y = index
			fwq[b] = index
			index++
		}
		if MAP[x][y] > time {	// 某些服务器对之间可能存在多个连接线
			MAP[x][y] = time
		}
	}
	// 多次迪杰斯特拉
	for i := 0; i < index; i++ {
		Dijkstra(i)
	}
	/*
		此时的邻接矩阵已被修改为最短路径状态数组
		如:MAP[i][j]代表结点i到j的最短路径
	*/
	var q int
	fmt.Scan(&q)
	// 交互输出
	for i := 0; i < q; i++ {
		var a, b string
		fmt.Scan(&a, &b)
		x, y := fwq[a], fwq[b]
		if MAP[x][y] == INF {
			fmt.Println("INF")
		} else {
			fmt.Println(MAP[x][y])
		}
	}
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值