leetcode1976_go_到达目的地的方案数

题目

你在一个城市里,城市由 n 个路口组成,路口编号为 0 到 n - 1 ,某些路口之间有 双向 道路。

输入保证你可以从任意路口出发到达其他任意路口,且任意两个路口之间最多有一条路。

给你一个整数 n 和二维整数数组 roads ,

其中 roads[i] = [ui, vi, timei] 表示在路口 ui 和 vi 之间有一条需要花费 timei 时间才能通过的道路。

你想知道花费 最少时间 从路口 0 出发到达路口 n - 1 的方案数。

请返回花费 最少时间 到达目的地的 路径数目 。由于答案可能很大,将结果对 109 + 7 取余 后返回。

示例 1:输入:n = 7, roads = [[0,6,7],[0,1,2],[1,2,3],[1,3,3],[6,3,3],[3,5,1],[6,5,1],[2,5,1],[0,4,5],[4,6,2]]

输出:4

解释:从路口 0 出发到路口 6 花费的最少时间是 7 分钟。

四条花费 7 分钟的路径分别为:

- 0 ➝ 6

- 0 ➝ 4 ➝ 6

- 0 ➝ 1 ➝ 2 ➝ 5 ➝ 6

- 0 ➝ 1 ➝ 3 ➝ 5 ➝ 6

示例 2:输入:n = 2, roads = [[1,0,10]] 输出:1

解释:只有一条从路口 0 到路口 1 的路,花费 10 分钟。

提示:1 <= n <= 200

n - 1 <= roads.length <= n * (n - 1) / 2

roads[i].length == 3

0 <= ui, vi <= n - 1

1 <= timei <= 109

ui != vi

任意两个路口之间至多有一条路。

从任意路口出发,你能够到达其他任意路口。

解题思路分析

1、Dijkstra+动态规划;时间复杂度O(n^2),空间复杂度O(n^2)

var mod = 1000000007

func countPaths(n int, roads [][]int) int {
   maxValue := int(1e11)   // math.MaxInt32=2147483647 才10位<200*1e9,可以使用11位或者更大
   arr := make([][]int, n) // 邻接矩阵:i=>j的最短距离
   for i := 0; i < n; i++ {
      arr[i] = make([]int, n)
      for j := 0; j < n; j++ {
         arr[i][j] = maxValue
      }
   }
   for i := 0; i < len(roads); i++ {
      a, b, c := roads[i][0], roads[i][1], roads[i][2]
      arr[a][b] = c
      arr[b][a] = c
   }
   dis := make([]int, n)
   for i := 0; i < n; i++ {
      dis[i] = maxValue
   }
   dis[0] = 0
   visited := make([]bool, n)
   for i := 0; i < n; i++ {
      target := -1 // 寻找未访问的距离起点最近点
      for j := 0; j < n; j++ {
         if visited[j] == false && (target == -1 || dis[j] < dis[target]) {
            target = j
         }
      }
      visited[target] = true
      for j := 0; j < n; j++ { // 更新距离
         dis[j] = min(dis[j], dis[target]+arr[target][j])
      }
   }
   // 计算某条边是否在边上
   edge := make([]int, n) // 入度
   for i := 0; i < n; i++ {
      for j := 0; j < n; j++ {
         if dis[i]+arr[i][j] == dis[j] {
            edge[j]++ // 入度+1
         }
      }
   }
   dp := make([]int, n) // dp[i] 表示0=>i的最短路个数
   dp[0] = 1
   queue := make([]int, 0)
   queue = append(queue, 0)
   for len(queue) > 0 {
      node := queue[0]
      queue = queue[1:]
      for j := 0; j < n; j++ {
         if dis[node]+arr[node][j] == dis[j] {
            dp[j] = (dp[j] + dp[node]) % mod
            edge[j]--         // 入度-1
            if edge[j] == 0 { // 入队
               queue = append(queue, j)
            }
         }
      }
   }
   return dp[n-1] % mod
}

func min(a, b int) int {
   if a > b {
      return b
   }
   return a
}

2、Floyd+递归;时间复杂度O(n^3),空间复杂度O(n^2)

var mod = 1000000007
var dp []int

func countPaths(n int, roads [][]int) int {
   maxValue := int(1e12)   // math.MaxInt32=2147483647 才10位<200*1e9,可以使用11位或者更大,这里使用11不行
   arr := make([][]int, n) // 邻接矩阵:i=>j的最短距离
   for i := 0; i < n; i++ {
      arr[i] = make([]int, n)
      for j := 0; j < n; j++ {
         arr[i][j] = maxValue
      }
      arr[i][i] = 0
   }
   for i := 0; i < len(roads); i++ {
      a, b, c := roads[i][0], roads[i][1], roads[i][2]
      arr[a][b] = c
      arr[b][a] = c
   }
   arr = Floyd(arr)
   path := make([][]int, n)
   dp = make([]int, n)
   for i := 0; i < n; i++ {
      path[i] = make([]int, 0)
      dp[i] = -1
   }
   // 构建图,都是从下标0开始
   for i := 0; i < len(roads); i++ {
      a, b, c := roads[i][0], roads[i][1], roads[i][2]
      if arr[0][b]-arr[0][a] == c {
         path[a] = append(path[a], b)
      } else if arr[0][a]-arr[0][b] == c {
         path[b] = append(path[b], a)
      }
   }
   return dfs(path, 0)
}

func dfs(path [][]int, index int) int {
   if index == len(path)-1 {
      return 1
   }
   if dp[index] != -1 {
      return dp[index]
   }
   dp[index] = 0
   for i := 0; i < len(path[index]); i++ {
      next := path[index][i]
      dp[index] = (dp[index] + dfs(path, next)) % mod
   }
   return dp[index]
}

func Floyd(arr [][]int) [][]int {
   n := len(arr)
   for k := 0; k < n; k++ {
      for i := 0; i < n; i++ {
         for j := 0; j < n; j++ {
            if arr[i][k]+arr[k][j] < arr[i][j] {
               arr[i][j] = arr[i][k] + arr[k][j]
            }
         }
      }
   }
   return arr
}

3、Floyd+动态规划;时间复杂度O(n^3),空间复杂度O(n^2)

leetcode1976_go_到达目的地的方案数

var mod = 1000000007

func countPaths(n int, roads [][]int) int {
   if n <= 2 {
      return 1
   }
   maxValue := int(1e12)   // math.MaxInt32=2147483647 才10位<200*1e9,可以使用11位或者更大,这里使用11不行
   arr := make([][]int, n) // 邻接矩阵:i=>j的最短距离
   dp := make([][]int, n)
   for i := 0; i < n; i++ {
      arr[i] = make([]int, n)
      dp[i] = make([]int, n)
      for j := 0; j < n; j++ {
         arr[i][j] = maxValue
      }
      arr[i][i] = 0
   }
   for i := 0; i < len(roads); i++ {
      a, b, c := roads[i][0], roads[i][1], roads[i][2]
      arr[a][b] = c
      arr[b][a] = c
      dp[a][b] = 1
      dp[b][a] = 1
   }
   for k := 0; k < n; k++ {
      for i := 0; i < n; i++ {
         if arr[i][k] == maxValue { // 不联通
            continue
         }
         for j := 0; j < n; j++ {
            // 不联通/距离大于当前值
            if arr[j][k] == maxValue || arr[i][k]+arr[k][j] > arr[i][j] {
               continue
            }
            if arr[i][k]+arr[k][j] < arr[i][j] {
               dp[i][j] = (dp[i][k] * dp[k][j]) % mod
               arr[i][j] = arr[i][k] + arr[k][j]
            } else if arr[i][k]+arr[k][j] == arr[i][j] {
               dp[i][j] = (dp[i][j] + dp[i][k]*dp[k][j]) % mod
            }
         }
      }
   }
   return dp[0][n-1]
}

4、Dijkstra+堆+动态规划;时间复杂度O(nlog(n)),空间复杂度O(n^2)

var mod = 1000000007

func countPaths(n int, roads [][]int) int {
   mathValue := int(1e12)
   arr := make([][][2]int, n)
   for i := 0; i < len(roads); i++ { // 邻接表
      a, b, c := roads[i][0], roads[i][1], roads[i][2]
      arr[a] = append(arr[a], [2]int{b, c})
      arr[b] = append(arr[b], [2]int{a, c})
   }
   dp := make([]int, n)
   dis := make([]int, n) // 0到其他点的距离
   for i := 0; i < n; i++ {
      dis[i] = mathValue
   }
   dis[0] = 0
   dp[0] = 1
   intHeap := make(IntHeap, 0)
   heap.Init(&intHeap)
   heap.Push(&intHeap, [2]int{0, 0})

   for intHeap.Len() > 0 {
      node := heap.Pop(&intHeap).([2]int)
      a, d := node[0], node[1]
      if dis[a] < d {
         continue
      }
      for i := 0; i < len(arr[a]); i++ {
         b, c := arr[a][i][0], arr[a][i][1]
         if dis[a]+c < dis[b] {
            dis[b] = dis[a] + c
            dp[b] = dp[a]
            heap.Push(&intHeap, [2]int{b, dis[b]})
         } else if dis[a]+c == dis[b] {
            dp[b] = (dp[b] + dp[a]) % mod
         }
      }
   }
   return dp[n-1] % mod
}

type IntHeap [][2]int

func (h IntHeap) Len() int {
   return len(h)
}

// 小根堆<,大根堆变换方向>
func (h IntHeap) Less(i, j int) bool {
   return h[i][1] < h[j][1]
}

func (h IntHeap) Swap(i, j int) {
   h[i], h[j] = h[j], h[i]
}

func (h *IntHeap) Push(x interface{}) {
   *h = append(*h, x.([2]int))
}

func (h *IntHeap) Pop() interface{} {
   value := (*h)[len(*h)-1]
   *h = (*h)[:len(*h)-1]
   return value
}

总结

Medium题目,最短路问题+动态规划,注意最大值的范围

展开阅读全文

页面更新:2024-05-18

标签:递归   下标   复杂度   最大值   整数   数组   示例   路径   路口   目的地   题目   道路   距离   时间   方案   动态   科技   空间

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2020-2024 All Rights Reserved. Powered By 71396.com 闽ICP备11008920号-4
闽公网安备35020302034903号

Top