贪心算法的汽车加油问题(使列表索引超出范围)

Posted

技术标签:

【中文标题】贪心算法的汽车加油问题(使列表索引超出范围)【英文标题】:Car Fueling Problem by Greedy Alogorithm (getting list index out of range) 【发布时间】:2020-08-17 14:25:40 【问题描述】:

我有一个使用贪心算法解决汽车加油问题的小问题。

问题介绍

您将前往位于 ???? 的另一个城市?离你的家乡几英里远。你的车可以旅行 最多 ????在满油箱上行驶英里,然后从满油箱开始。一路上,距离 stop1 stop2 有加油站。 . . ,stopN 从你的家乡。最少需要补充多少次?

输入:

950
400
4
200 375 550 750

输出:

2

我目前所尝试的

def car_fueling(dist,miles,n,gas_stations):
  num_refill, curr_refill, last_refill = 0,0,0
  while curr_refill <= n:
    last_refill = curr_refill
    while (curr_refill <= n-1) & (gas_stations[curr_refill + 1] - gas_stations[last_refill] <= miles):
        curr_refill += 1
    if curr_refill == last_refill:  
      return -1
    if curr_refill <= n:
      num_refill += 1
  return num_refill

我面临的问题是什么

在声明中

while (curr_refill <= n-1) & (gas_stations[curr_refill + 1] - gas_stations[last_refill] <= miles)

我收到错误IndexError: list index out of range。这是因为gas_stations[curr_refill + 1]。因此,当我尝试将其分隔为 while 循环和 if 语句时,如

while (curr_refill <= n-1):
    if (gas_stations[curr_refill + 1] - gas_stations[last_refill] <= miles):
        curr_refill += 1
    else:
        break

它正在进入一个无限循环。

您能指出我面临的错误吗?

提前致谢。

【问题讨论】:

我不确定这是否是有意的,但 & 运算符在 python 中不是 AND。如果你想使用逻辑并使用关键字“and”,而不是&。但对我来说,您似乎正在尝试使用短路评估,因此如果左边的条件已经为假,则不会检查正确的条件,从而防止索引超出范围错误。 感谢您的回复,只是为了澄清一下,如果您说如果我使用 and 而不是 &amp; 那么条件 gas_stations[curr_refill + 1] - gas_stations[last_refill] &lt;= miles 将不会检查如果条件 curr_refill &lt;= n-1 这是错误,然后我尝试它不起作用仍然得到相同的list out of index error 数组中的第一个索引是 0 还是 1? 数组gas_stations从0开始。 将 while (curr_refill gas_stations[n],它超出了最后一个索引。也删除等号 while 条件,使其变为 while curr_refill 【参考方案1】:

我使用此代码并从 Coursera 的一门课程中得到了正确答案。

# python3
import sys

def compute_min_refills(distance, tank, stops):
    capacity_tank = tank
    refill = 0

    if capacity_tank >= distance:
        return 0
    if capacity_tank < stops[0] or (distance-stops[-1]) > capacity_tank:
        return -1

    for i in range(1, len(stops)):
        if (stops[i]-stops[i-1]) > capacity_tank:
            return -1
        if stops[i] > tank:
            tank = (stops[i-1] + capacity_tank)
            refill += 1
    if distance > tank:
        refill += 1

    return refill


    if __name__ == '__main__':
        d, m, _, *stops = map(int, sys.stdin.read().split())
        print(compute_min_refills(d, m, stops))

【讨论】:

【参考方案2】:

将 [0] 和 [d] 添加到停靠点的答案应该有效,但 current_refill 比较应该在任何地方都是 current_refill &lt; len(stops)- 2,因为添加了两个停靠点。 还有另一种方法可以解决这个问题。

def compute_min_number_of_refills(d, m, stops):
    if d <= m:
        return 0
    total_refill = 0
    last_refill = -1
    limit = m 
    stops.append(d)
    i = 0
    while i < len(stops):
        if stops[i] >= limit: 
            current_refill = i - 1 if stops[i] > limit else i
            if current_refill == last_refill:
                return -1 
            last_refill = current_refill
            total_refill += 1
            limit = m + stops[current_refill]
            i = current_refill + 1
        else:
            i += 1
    return total_refill

【讨论】:

【参考方案3】:

导入 java.util.; 导入 java.io.;

公共课 CarFueling

static int compute_refills(int dist, int tank, int stops[], int n) 
    int current_refills=0;
    int num_refills=0;
    int last_refill=0;
    while(current_refills<=n) 
        last_refill = current_refills;
        while ((current_refills !=stops.length-1) && (stops[current_refills + 1] - stops[last_refill]) <= tank) 
            current_refills +=1 ;

        

        if (current_refills == last_refill)
            return -1;
        if (current_refills <= n)
            num_refills +=1;


    
    return num_refills;




    public static void main (String[]args)
        Scanner scanner = new Scanner(System.in);
        int dist = scanner.nextInt();
        int tank = scanner.nextInt();
        int n = scanner.nextInt();
        int stops[] = new int[n * n * n];// to solve array index out of bound exception increase the size of the array
        for (int i = 0; i < n; i++) 
            stops[i] = scanner.nextInt();
        

        System.out.println(compute_refills(dist, tank, stops, n));

    

【讨论】:

我已经在 java 中实现了。但是,我认为while循环的迭代存在一些问题。效果不好【参考方案4】:

这可能会修复索引错误。您的代码逻辑是正确的,这与我在 else 语句块中的代码中所做的相同。添加起点和终点(总距离)可以避免索引错误。首先检查总距离,看是否可以装满油箱到达。如果不做 else 语句。

def compute_min_refills(distance, tank, stops):

    numrefill, currentrefill= 0,0
    stops = [0] + stops + [distance] #include the start and end points in the stops list   
    if distance <= tank:
        return 0
    else:
        while currentrefill < len(stops)-1:
            lastrefill = currentrefill
            #print(currentrefill, lastrefill, len(stops))
            while currentrefill < len(stops)-1 and stops[currentrefill+1] - stops[lastrefill]<=tank:
           
                currentrefill += 1

            if currentrefill == lastrefill:
                return -1
            if currentrefill < len(stops)-1:
                numrefill +=1

        #print(numrefill)

        return numrefill

if __name__ == '__main__':
    
    #print(compute_min_refills(10, 3, [1,2,5,9]))

【讨论】:

没有任何解释的代码转储很少有帮助。 Stack Overflow 是关于学习的,而不是提供 sn-ps 来盲目复制和粘贴。请edit您的问题并解释它如何比OP提供的更好。见How to Answer。 我以为问这个问题的作者实际上知道代码的逻辑,他/她唯一的问题是索引。所以我将起点添加为 0,还包括终点,这将使这个问题易于理解。此外,我创建的变量的名称非常明显。我认为这会对这个问题有所帮助。【参考方案5】:

我不知道为什么,但答案似乎过于复杂,我只是想象自己开车并想出了这个简单的解决方案

function minfill(distance, miles, n, stations) 

    //added final distance to last station for simplicity can simply push to array. 
    stations = [...stations, distance]

    let refill = 0,
        limit = miles,
        dt = 0, //distance travelled
        current = 0; //current station

    while (current <= n) 

        //check if next  or first station is unreachable
        if ((Math.abs(stations[current] - stations[current + 1]) > limit) || stations[0] > limit) return -1

        //check if we need to refuel or pass
        if (Math.abs(dt - stations[current]) <= limit)  
            current++
        

        //if next distance was over limit we set distance tavelled to previous station ,current station was already pointed to next in above block
        else 
            dt = stations[current - 1]

            refill++
        
    
    return refill

p.s-这段代码是用 node/javascript 编写的,虽然我已经通过了这个问题的所有测试,但我知道这里有更聪明的人会帮助改进/纠正这段代码或提供一些指导。

【讨论】:

【参考方案6】:
def car_refill(dist,cap,n,stops):
    stops.insert(0,0)
    stops.append(dist)
    num_refill,curr_refill = 0,0
    while curr_refill <= n:
        last_refill = curr_refill
        while (curr_refill <= n and stops[curr_refill + 1] - stops[last_refill] <= cap):
            curr_refill += 1
        if curr_refill == num_refill :
            return -1
        if curr_refill <= n:
            num_refill +=1
    return num_refill

试试这个....

【讨论】:

感谢您的回答,欢迎来到 ***! =) 我们来这里是为了学习一些东西,所以请评论您的贡献并向读者解释您编写了什么以及为什么编写了一些代码 对不起,我是新手,所以不太熟悉规范,这与上面的代码工作方式相同,但它也认为 x 是从零开始到目的地的一维矩阵,然后我们使用内部 while 循环到达最远点,如果没有点 num_refill 和 curr_refill 将保持不变,所以 -1 否则我们可以去增加 num_refill 意味着我们填满水箱【参考方案7】:

几个问题:

&amp; 不是布尔和运算符。使用and curr_refill + 1 可以是 n,因此会产生你得到的错误。请注意,last 加油站之后的距离可以使用dist 确定 last_refill 的值从一开始就是错误的:您还没有在 0 站重新填充,因此不应将其初始化为 0。而是使用另一个变量来表示您当前可以行驶多远。李>

更正的代码:

def car_fueling(dist,miles,n,gas_stations):
    num_refill, curr_refill, limit = 0,0,miles
    while limit < dist:  # While the destination cannot be reached with current fuel
        if curr_refill >= n or gas_stations[curr_refill] > limit:
            # Cannot reach the destination nor the next gas station
            return -1
        # Find the furthest gas station we can reach
        while curr_refill < n-1 and gas_stations[curr_refill+1] <= limit:
            curr_refill += 1
        num_refill += 1  # Stop to tank
        limit = gas_stations[curr_refill] + miles  # Fill up the tank 
        curr_refill += 1
    return num_refill

# Test cases
print(car_fueling(950, 400, 4, [200, 375, 550, 750]))  # 2
print(car_fueling(10, 3, 4, [1, 2, 5, 9]))  # -1

【讨论】:

感谢您的回复。该代码在有解决方案的情况下完美运行,但对于输出为 -1 的情况,它正在进入无限循环。例如:输入car_fueling(10, 3, 4, [1, 2, 5, 9]) 输出:-1 添加了 curr_refill 的缺失增量并添加了退出条件。 谁能解释为什么@trincot 使用current_refill &lt; n-1 而不仅仅是current_refill &lt; n @Andrew,简短回答:如果我们有 current_refill &lt; n,那么下一个条件 gas_stations[curr_refill+1] 可能会导致超出范围的索引,因为该索引可以评估为 n)。更长的答案:我们可以在current_refill == n-1 时停止循环,因为这意味着我们在最后一个加油站。我们已经知道如果不加油(外环条件)我们没有足够的燃料到达目的地,所以我们必须考虑在这里加油:这是我们唯一剩下的机会。【参考方案8】:

它处于无限循环中,因为 n 没有递增。

在最有意义的地方增加 n(例如,在 while 语句的末尾)。

def car_fueling(dist,miles,n,gas_stations):
    num_refill, curr_refill, last_refill = 0,0,0

    while curr_refill <= n:
        last_refill = curr_refill

        while (curr_refill <= n-1) & (gas_stations[curr_refill + 1] - gas_stations[last_refill] <= miles):
            curr_refill += 1
        if curr_refill == last_refill:  
            return -1
        if curr_refill <= n:
            num_refill += 1

        n+=1 # Increment

  return num_refill

【讨论】:

感谢您的回答,但此解决方案提供的列表索引超出范围错误。 我很抱歉。我认为您的问题集中在解决无限循环上。我现在看到这是一个关于实现贪心算法的问题。

以上是关于贪心算法的汽车加油问题(使列表索引超出范围)的主要内容,如果未能解决你的问题,请参考以下文章

贪心算法之虚拟汽车加油问题

贪心算法求解汽车加油问题

汽车加油问题--贪心算法

贪心算法--汽车加油问题

汽车加油问题(贪心算法),O(n) 复杂度的嵌套 while 循环

[贪心算法]加油站