网易首页 > 网易号 > 正文 申请入驻

2026-10-02:有限电量到达目标节点的最少时间。用go语言,给定一张包含 n 个顶点的带权有向图,顶点编号为 0 到 n-1。图中的边由 edges

0
分享至

2026-10-02:有限电量到达目标节点的最少时间。用go语言,给定一张包含 n 个顶点的带权有向图,顶点编号为 0 到 n-1。图中的边由 edges 表示,每条边 [u, v, t] 表示从顶点 u 指向顶点 v,经过这条边需要耗时 t 秒。另有一个初始电量 power、一个长度为 n 的数组 cost,以及起点 source 和终点 target。cost[u] 表示信号要从顶点 u 沿任意一条出边继续发送时,需要消耗的电量。

信号在第 0 秒从 source 出发,初始电量为 power。到达某个顶点时不会扣电;只有当信号准备离开该顶点、沿某条出边继续前进时,才需要先保证当前剩余电量不少于 cost[u],然后剩余电量减少 cost[u]。每经过一条边,累计时间增加这条边的耗时。

现在要求计算信号从 source 到 target 的可行路径。优先使到达 target 的总时间最小;如果存在多条路径都能达到这个最小总时间,则选择到达 target 时剩余电量最大的那条路径。返回一个包含两个整数的结果:第一个是最小总时间,第二个是该最小总时间下的最大剩余电量。如果信号无法到达 target,则返回 [-1, -1]。

1 <= n <= 1000。

0 <= edges.length <= 1000。

edges[i] = [ui, vi, ti]。

0 <= ui, vi <= n - 1。

1 <= ti <= 100000。

1 <= power <= 1000。

cost.length == n。

1 <= cost[i] <= 2000。

0 <= source, target <= n - 1。

输入: n = 5, edges = [[0,1,1],[1,4,1],[0,2,1],[2,3,1],[3,4,1]], power = 4, cost = [2,3,1,1,1], source = 0, target = 4。

输出: [3,0]。

解释:

信号从节点 0 出发,拥有 4 个单位的电量。

路径 0 -> 1 -> 4 无效,因为离开节点 0 后,信号剩余 2 个单位的电量,这小于 cost[1] = 3。

有效路径 0 -> 2 -> 3 -> 4 总共花费时间为 3。

沿着这条路径消耗的总电量为 cost[0] + cost[2] + cost[3] = 4,剩余电量为 0。

因此,答案为 [3, 0]。

题目来自力扣3977。

1. 把图整理成邻接表

首先,代码把输入的边数组edges转换成邻接表。

每一条边[u, v, t]表示:

  • • 从节点u出发;

  • • 可以到达节点v;

  • • 经过这条边需要花费t秒。

于是,对于每个节点u,都会保存一个列表,里面记录所有从u出发的边,以及每条边到达的目标节点和耗时。

这样做的目的,是后面从某个节点扩展路径时,可以快速找到它的所有出边。

2. 定义动态规划状态

代码使用一个二维数组来记录状态,含义是:

f[rem][u] 表示:从起点 source 出发,到达节点 u 时,如果剩余电量恰好是 rem,那么累计花费的最小时间是多少。

也就是说,第一维表示剩余电量,第二维表示当前所在节点,值表示最小总时间。

初始化时:

  • • 在起点source,一开始剩余电量是power,时间为0;

  • • 所以f[power][source] = 0;

  • • 其他所有状态都初始化为一个很大的数,表示暂时不可达。

这个状态定义很关键,因为它同时记录了“剩余电量”和“到达节点”,可以区分同样到达某个节点但剩余电量不同的情况。

3. 从高电量向低电量遍历

接下来,代码从剩余电量power开始,一直递减到0,逐层处理。

为什么从高到低?

因为信号每离开一个节点,都会消耗该节点的cost[u],而cost[u]是正数。所以:

  • • 从高剩余电量状态出发,只会转移到更低剩余电量的状态;

  • • 不会从低电量转移到高电量。

因此,按照剩余电量从高到低遍历,可以保证:

  • • 当处理某个剩余电量rem时,所有能到达该状态的前驱状态都已经被处理过了;

  • • 用当前状态去更新更低剩余电量的状态,是安全的,不会遗漏或重复。

这本质上是一种按剩余电量分层的动态规划。

4. 每一层剩余电量的处理过程

对于每一个剩余电量rem,代码做两件事:

第一件事:检查是否能到达目标节点

如果f[rem][target]不是无穷大,说明在剩余电量为rem的情况下,可以到达终点target,并且记录了一个总时间。

此时代码会比较这个时间与当前已经记录的全局最小时间minDis:

  • • 如果f[rem][target] < minDis,说明找到了更短的到达时间;

  • • 于是更新minDis为这个更短时间;

  • • 同时把maxRem更新为当前的剩余电量rem。

由于外层循环是从power递减到0,所以:

  • • 剩余电量大的状态会先被检查;

  • • 如果后面出现相同的最小时间,但剩余电量更小,因为判断条件是严格小于,所以不会覆盖;

  • • 因此最终保留的maxRem是所有达到最小时间的路径中,剩余电量最大的那个。

这正好满足题目要求:先最小时间,再最大剩余电量。

第二件事:从当前状态向外扩展

接着,代码遍历所有节点x,查看f[rem][x]是否可达。

如果f[rem][x]是无穷大,说明在剩余电量为rem时无法到达节点x,直接跳过。

如果可达,还要判断当前剩余电量rem是否足够支付离开节点x所需的电量,也就是是否满足:

rem >= cost[x]

只有满足这个条件,信号才能从节点x沿任意一条出边继续前进。

如果满足,则计算离开后的剩余电量:

nxtRem = rem - cost[x]

然后遍历节点x的所有出边。对于每一条出边x -> to,耗时为t:

  • • 当前到达x的最小时间是f[rem][x];

  • • 经过这条边后,到达to的时间是f[rem][x] + t;

  • • 新的剩余电量是nxtRem;

  • • 如果这个时间比f[nxtRem][to]原来记录的时间更小,就更新它。

这一步就是所谓的“刷表法”:用当前已经确定的状态,去松弛它能到达的后继状态。

注意:到达某个节点本身不消耗电量,只有离开该节点时才消耗。因此这里是在“准备离开节点x”时扣除cost[x]。

5. 为什么到达 target 后不需要再检查 cost

代码在检查f[rem][target]时,只关心是否能到达终点,并不要求rem >= cost[target]。

这是合理的,因为:

  • • 信号到达target后已经完成任务;

  • • 不需要再从target离开;

  • • 所以不需要支付cost[target]。

因此,只要某个剩余电量下能到达target,就是一个合法结果。

6. 最终结果判断

当所有剩余电量都处理完后:

  • • 如果maxRem仍然是-1,说明从来没有到达过target,返回[-1, -1];

  • • 否则返回[minDis, maxRem],其中:

    • •minDis是最小总时间;

    • •maxRem是在这个最小总时间下,到达终点时最大的剩余电量。

对于题目给的例子:

  • • 路径0 -> 2 -> 3 -> 4总时间为3;

  • • 消耗电量为cost[0] + cost[2] + cost[3] = 2 + 1 + 1 = 4;

  • • 初始电量为4,所以剩余电量为0;

  • • 因此输出[3, 0]。

7. 正确性简要说明

这个算法覆盖了所有可能的路径,因为:

  • • 状态中包含了“当前节点”和“剩余电量”;

  • • 每次扩展都严格按照消耗电量的规则进行;

  • • 电量只会减少,所以按电量从高到低处理不会漏掉任何可达状态;

  • • 对于每个状态,只保留到达该状态的最小时间;

  • • 最终在全局最小时间的前提下,由于遍历顺序是从高电量到低电量,所以保留的是最大剩余电量。

因此,算法能够得到题目要求的结果。

8. 时间复杂度

设:

  • • 节点数为n;

  • • 边数为m;

  • • 初始电量为power。

代码外层循环剩余电量,共power + 1次。

每次外层循环中:

  • • 遍历所有节点,检查状态,复杂度为O(n);

  • • 对于可达且满足电量条件的节点,遍历其所有出边,所有出边总和最多为m,复杂度为O(m)。

所以每一层剩余电量的处理复杂度是O(n + m)。

总时间复杂度为:

O(power * (n + m))

代入题目限制,power <= 1000,n <= 1000,m <= 1000,规模大约在百万级别,是可以接受的。

9. 额外空间复杂度

主要额外空间包括:

  • • 动态规划状态表f,大小为(power + 1) * n,所以是O(power * n);

  • • 邻接表存储图,节点数为n,边数为m,所以是O(n + m)。

因此总额外空间复杂度为:

O(power * n + n + m)

通常可以简写为:

O(power * n + m)

因为n已经被power * n覆盖。

总结一下:

这个算法用“剩余电量”作为动态规划的一维,用“当前节点”作为另一维,记录到达每个状态的最小时间。然后从高电量到低电量逐层扩展,优先保证总时间最小,再在相同总时间下保留最大剩余电量。时间复杂度为O(power * (n + m)),额外空间复杂度为O(power * n + m)。

Go完整代码如下:

package main

import (
"fmt"
"math"
)

func minTimeMaxPower(n int, edges [][]int, power int, cost []int, source int, target int) []int64 {
type edge struct{ to, t int }
g := make([][]edge, n)
for _, e := range edges {
x, y, t := e[0], e[1], e[2]
g[x] = append(g[x], edge{y, t})
}

f := make([][]int, power+1)
for i := range f {
f[i] = make([]int, n)
for j := range f[i] {
f[i][j] = math.MaxInt
}
}
f[power][source] = 0

minDis, maxRem := math.MaxInt, -1
for rem := power; rem >= 0; rem-- {
if f[rem][target] < minDis {
minDis, maxRem = f[rem][target], rem
}
for x, v := range f[rem] {
if v == math.MaxInt || rem < cost[x] {
continue
}
nxtRem := rem - cost[x]
for _, e := range g[x] {
f[nxtRem][e.to] = min(f[nxtRem][e.to], v+e.t) // 刷表法
}
}
}

if maxRem < 0 {
return []int64{-1, -1}
}
return []int64{int64(minDis), int64(maxRem)}
}

func main() {
n := 5
edges := [][]int{{0, 1, 1}, {1, 4, 1}, {0, 2, 1}, {2, 3, 1}, {3, 4, 1}}
power := 4
cost := []int{2, 3, 1, 1, 1}
source := 0
target := 4
result := minTimeMaxPower(n, edges, power, cost, source, target)
fmt.Println(result)
}

Python完整代码如下:

# -*-coding:utf-8-*-

from typing import List

def minTimeMaxPower(
n: int,
edges: List[List[int]],
power: int,
cost: List[int],
source: int,
target: int
) -> List[int]:
g = [[] for _ in range(n)]
for u, v, t in edges:
g[u].append((v, t))

INF = 10**30
f = [[INF] * n for _ in range(power + 1)]
f[power][source] = 0

min_dis = INF
max_rem = -1

for rem in range(power, -1, -1):
if f[rem][target] < min_dis:
min_dis = f[rem][target]
max_rem = rem

for x, cur_time in enumerate(f[rem]):
if cur_time == INF or rem < cost[x]:
continue

nxt_rem = rem - cost[x]
for to, t in g[x]:
new_time = cur_time + t
if new_time < f[nxt_rem][to]:
f[nxt_rem][to] = new_time

if max_rem < 0:
return [-1, -1]

return [min_dis, max_rem]

if __name__ == "__main__":
n = 5
edges = [[0, 1, 1], [1, 4, 1], [0, 2, 1], [2, 3, 1], [3, 4, 1]]
power = 4
cost = [2, 3, 1, 1, 1]
source = 0
target = 4

result = minTimeMaxPower(n, edges, power, cost, source, target)
print(result)

C++完整代码如下:

  

using namespace std;


vector minTimeMaxPower(
int n,
vector int >>& edges,
int power,
vector< int >& cost,
int source,
int target
) {
struct Edge {
int to, t;
};

vector > g(n);
for (auto& e : edges) {
int x = e[ 0 ], y = e[ 1 ], t = e[ 2 ];
g[x].push_back({y, t});
}

const long long INF = LLONG_MAX / 4 ;

// f[rem][u] 表示到达节点 u 且剩余电量为 rem 时的最小时间
vector > f(power + 1 , vector (n, INF));
f[power][source] = 0 ;

long long minDis = INF;
int maxRem = -1 ;

for ( int rem = power; rem >= 0 ; --rem) {
if (f[rem][target] < minDis) {
minDis = f[rem][target];
maxRem = rem;
}

for ( int x = 0 ; x < n; ++x) {
long long curTime = f[rem][x];
if (curTime == INF || rem < cost[x]) {
continue ;
}

int nxtRem = rem - cost[x];
for (auto& e : g[x]) {
if (curTime + e.t < f[nxtRem][e.to]) {
f[nxtRem][e.to] = curTime + e.t;
}
}
}
}

if (maxRem < 0 ) {
return { -1 , -1 };
}

return {minDis, (long long)maxRem};
}

int main() {
int n = 5 ;
vector int >> edges = {
{ 0 , 1 , 1 },
{ 1 , 4 , 1 },
{ 0 , 2 , 1 },
{ 2 , 3 , 1 },
{ 3 , 4 , 1 }
};
int power = 4 ;
vector< int > cost = { 2 , 3 , 1 , 1 , 1 };
int source = 0 ;
int target = 4 ;

vector result = minTimeMaxPower(n, edges, power, cost, source, target);
cout << "[" << result[ 0 ] << ", " << result[ 1 ] << "]" << endl;

return 0 ;
}

我们相信人工智能为普通人提供了一种“增强工具”,并致力于分享全方位的AI知识。在这里,您可以找到最新的AI科普文章、工具评测、提升效率的秘籍以及行业洞察。 欢迎关注“福大大架构师每日一题”,发消息可获得面试资料,让AI助力您的未来发展。

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
郑丽文真高明、“内鬼”自讨苦吃!卢秀燕后悔,不该做错一个决定

郑丽文真高明、“内鬼”自讨苦吃!卢秀燕后悔,不该做错一个决定

野史日记
2026-10-13 07:00:20
开心!郑钦文中网夺冠开启买买买模式,逛Dior店拎着大包小包出门

开心!郑钦文中网夺冠开启买买买模式,逛Dior店拎着大包小包出门

818体育
2026-10-13 12:44:39
最高奖金破千万,本赛季金花赚翻了!

最高奖金破千万,本赛季金花赚翻了!

网球之家
2026-10-13 15:09:50
郭碧婷爸爸晒孙子正脸照,4岁向笙浓眉大眼很漂亮,留长发像女娃

郭碧婷爸爸晒孙子正脸照,4岁向笙浓眉大眼很漂亮,留长发像女娃

小疯子耶
2026-10-13 10:57:05
苹果10月27日连开两天,四款新品一次亮相

苹果10月27日连开两天,四款新品一次亮相

报错免疫体
2026-10-13 00:56:56
约基奇评NBA总统山:库里入选,詹姆斯落选引争议

约基奇评NBA总统山:库里入选,詹姆斯落选引争议

篮坛第一线
2026-10-14 03:49:59
女性心中理想的性生活时长曝光,男性看完沉默了

女性心中理想的性生活时长曝光,男性看完沉默了

精彩分享快乐
2026-10-02 21:00:07
福建一市民政局原党组书记、局长、四级调研员被查

福建一市民政局原党组书记、局长、四级调研员被查

大闽门户
2026-10-13 21:14:35
天津这一刀,砍向了楼市的命脉

天津这一刀,砍向了楼市的命脉

大川东山再起
2026-10-13 14:35:25
为什么公司一出现“单车棚效应” ,就离倒闭不远了?

为什么公司一出现“单车棚效应” ,就离倒闭不远了?

互联网思维
2026-10-11 23:38:51
麻将馆老板的忠告:天天准点来打牌的女人,最后都没能留住什么

麻将馆老板的忠告:天天准点来打牌的女人,最后都没能留住什么

林子说事
2026-10-13 20:45:13
王皓事件升级:骂王皓的那三个女孩,被行拘仅是开胃菜,更严重的后果还在后面

王皓事件升级:骂王皓的那三个女孩,被行拘仅是开胃菜,更严重的后果还在后面

法网恢恢
2026-10-11 22:07:22
红毯土疯了!马伊琍穿成地摊货 倪萍似地主婆 宋佳礼服写满野心

红毯土疯了!马伊琍穿成地摊货 倪萍似地主婆 宋佳礼服写满野心

一盅情怀
2026-10-11 14:46:29
世卫组织呼吁:停止使用电热水壶,否则会诱发癌症?告诉你真相!

世卫组织呼吁:停止使用电热水壶,否则会诱发癌症?告诉你真相!

芹姐说生活
2026-09-07 22:31:08
看完胜利3-1费尔干纳油工,不得不承认5个事实,C罗轰生涯981球!

看完胜利3-1费尔干纳油工,不得不承认5个事实,C罗轰生涯981球!

田先生篮球
2026-10-13 05:57:57
上甘岭坑道最禁忌的一夜:17岁女卫生员用嘴吸出战友尿液,秦基伟回忆录曝光真相

上甘岭坑道最禁忌的一夜:17岁女卫生员用嘴吸出战友尿液,秦基伟回忆录曝光真相

纪史行者
2026-10-08 05:10:03
普通储户请做好准备:2027年接下来,银行存款利率或将重演2016年的行情

普通储户请做好准备:2027年接下来,银行存款利率或将重演2016年的行情

叮当当科技
2026-10-13 18:38:51
一直以为街边收旧手机的,是搞提炼"黄金"。结果却错得离谱!那淘汰下来的破手机,最后到底去哪了?不查不知道,一查惊出一身冷汗。

一直以为街边收旧手机的,是搞提炼"黄金"。结果却错得离谱!那淘汰下来的破手机,最后到底去哪了?不查不知道,一查惊出一身冷汗。

回京历史梦
2026-10-08 04:15:04
一周后揭幕战:76人最后一场季前赛定在周五

一周后揭幕战:76人最后一场季前赛定在周五

林间小温柔
2026-10-14 06:10:22
谢贤前女友Coco直播被说丑,本人回应:“姐都40岁了,把头发往下一放还是迷倒一大片的”

谢贤前女友Coco直播被说丑,本人回应:“姐都40岁了,把头发往下一放还是迷倒一大片的”

韩小娱
2026-09-04 05:54:22
2026-10-14 06:51:00
moonfdd incentive-icons
moonfdd
福大大架构师每日一题
1513文章数 83关注度
往期回顾 全部

科技要闻

扎克伯格宣布追上OpenAI!Meta新模型亮相

头条要闻

男子到姐姐家调解夫妻矛盾 不到1分钟被姐夫刺死

头条要闻

男子到姐姐家调解夫妻矛盾 不到1分钟被姐夫刺死

体育要闻

走调的歌声里全是感情 最好的郑钦文尚未登场

娱乐要闻

谭松韵亲自解答兰香结局遗憾

财经要闻

"黑医师"产业链调查:不学医竟能"拿证"

汽车要闻

豪华智能全拉满 比亚迪大汉不止旗舰级舒适

态度原创

家居
本地
数码
亲子
房产

家居要闻

2026建博会(广州) 公装联探展交流活动

本地新闻

这个十一,林都伊春彻底出圈!

数码要闻

苹果发布智能家居设备HomeView:搭载Siri AI与7英寸显示屏

亲子要闻

孕期可以有性生活吗?一次说清楚

房产要闻

巨无霸来了!海口百亿大盘,正式动工!

无障碍浏览 进入关怀版