题目描述
你正在驾驶一辆电动车从上海前往北京,途中在距离上海x1, x2, …, xn处有充电站。
由于等待时间c和充电速度g的不同,在充电站xi处为电动车充电k公里的电量需要ci + kgi分钟。
你的车有足够的容量一次充满电后行驶400公里。假设车辆在上海的第一个充电站x1开始时电池电量为0,xn是你在北京的目的地。
设计一个高效的算法,找出你应该在哪里停下来,在充电站花费的时间最少。
样例
Input:
x = [0, 100, 300, 600, 800, 1000]
c = [0, 10, 0, 20, 10, 0]
g = [0.05, 0.2, 0.1, 0.2, 0.1, 0]
Output:
[20,0,30,40,30,0]
在提供的示例中,共有6个充电站。目标是从第一个站点驾驶到最后一个站点,优化在每个站点的花费时间。输出详细说明了在每个站点花费的时间,旨在最小化整个旅程中的总时间。例如,在第一个站点花费的时间计算为0 + 400 * 0.05 = 20分钟。你应该有一个名为timeSpent的函数,用来接收距离x(List[int])、等待时间c(List[int])、充电速度g(List[int])的信息,并返回在每个站点花费的时间t(List[int])。
题解 ——by: GoesM
思路
考虑油量状态最高为400,所以可以将其纳入dp的状态信息中,期待最终的带常数的复杂度约为O(400*n)
线性复杂度在dp问题中基本够用,所以继续延续这个思路:
dp更新等式
dp[i][j]
表示到达i点
,油量剩余为j
的最优解- 每个状态走到下一站的时候只有两种选择:本地加油,或者不加油
dp[i][j+k] = min(dp[i][j+k], dp[i][j]+c[i]+k*g[i])
: 在位置i
剩余油量为j
时,加k公里油
- 完成dp等式构建√
难点
发现本题的dp构思并不难,难在需要记录dp更新的路径,所以就有了下面很丑的代码
INF = int(1e9)
def timeSpent(x, c, g):
n = len(x)
dp = [[INF] * 401 for _ in range(n)] # 初始化动态规划数组,范围从0到400
nex = [[(-1,-1)] * 401 for _ in range(n)] # 记录dp[i][j]是由哪个状态更新的
# 初始化第一个站点
for j in range(401):
if j==0:
dp[0][j] = 0
else:
dp[0][j] = c[0] + j * g[0]
nex[0][j] = (0,0)
# 动态规划递推
for i in range(1, n): # 想要到i
distance = x[i] - x[i-1]
for j in range(401): # 在i-1时的油量
if(j<distance): # 不够
pass
else: # 足够
dp[i][j-distance] = dp[i-1][j] # 无需加油
nex[i][j-distance] = (i-1,j) # 状态路径
for j in range(401):
if(dp[i][j] < INF ):
for k in range(401): # 在当前状态下,加k公里油
if( k+j > 400 ):
break
else:
if(dp[i][j+k]>dp[i][j] + c[i]+k*g[i] ):
dp[i][j+k] = min(dp[i][j+k], dp[i][j]+c[i]+k*g[i])
nex[i][j+k] = (i,j)
else:
pass
else: # 当前状态不存在,跳过
pass
# 选取最佳结果的那个最终状态
now_state = (0,0)
minx = INF
for i in range(401):
if (dp[n-1][j]< minx):
minx = dp[n-1][j]
now_state = (n-1,j)
else:
pass
t = [0] * n
while( now_state[0]!=-1 ):
pos = now_state[0]
left = now_state[1]
nex_state = nex[pos][left]
nex_pos = nex_state[0]
nex_left = nex_state[1]
if(nex_pos==pos-1):
pass
else: # 说明加油了
t[pos] += c[pos]+(left-nex_left)*g[pos]
now_state = nex_state
# print(int(round(minx))) # check if sum is correct
for i in range(len(t)):
t[i] = round(t[i])
return t
日常反思,为什么我高中的时候学不会dp啊,简直对自己无语了…