您有一辆卡车在圆形轨道上移动,加油站围绕圆圈间隔开。每个站都有有限的气体。卡车上的油箱无限大。加油站之间的距离需要一定量的气体穿过。你只能向一个方向移动。
使用什么算法? 你从哪个加油站开始? 你可以一路走回起跑站吗?
答案 0 :(得分:24)
是O(n)是可能的。绝对不是TSP。
设x i 是站i的可用气体量减去前往下一站所需的气体量。
要求是Σx i ≥0(足以完成整圆的气体)。
考虑S i = x 1 + x 2 + ... + x i
注意S n ≥0。
现在选择最小的(或者甚至是最大的将会更容易编写代码)k使得S k 是最小的并且从它旁边的站开始。
现在对于k < j≤n,我们有坦克中的气体= S j - S k ≥0。
对于1≤j≤k,我们在罐中有气体= x k + 1 + .. + x n + x 1 + x 2 + .. + x j = S n - S k + S j < / sub>≥0。
因此从k + 1开始将确保每个站点有足够的气体到达下一站。
// C++ code. gas[i] is the gas at station i, cost[i] is the cost from station i to (i+1)%n
int circ(vector<int> &gas, vector<int> &cost) {
int min_S=INT_MAX, S=0, position=0;
for(int i=0;i<gas.size();i++)
{
S += gas[i] - cost[i];
if(S<min_S)
{
min_S = S;
position = (i+1) % gas.size();
}
}
if(S>=0)
return position;
else
return -1;
}
答案 1 :(得分:11)
这是一种在O(n)
时间和O(1)
空间中工作的方法(与Aryabhatta的答案相对于O(n)
空间)。
从任何一个站点开始,将其称为0站点,然后前进,直到您的燃气耗尽。如果你没有用完汽油,那就完成了。否则,如果在k和k + 1站之间用完,请在站k + 1处重新开始。如果再次传递0,请记下,如果在此之后用完,则无法完成。
这样做的原因是因为如果你从车站i开始并且在车站k和k + 1之间耗尽汽油,那么如果你从i和i之间的任何车站开始,那么你也将在车站k + 1之前耗尽汽油。 ķ。
这是一个算法,给定一个数组P(汽油)和D(距离):
int position = 0;
int petrol = P[0];
int distance = D[0];
int start = 0;
while (start < n) {
while (petrol >= distance) {
petrol += P[++position % N] - distance;
distance = D[position % N];
if (position % N == start)
return start;
}
start = position;
petrol = P[start];
}
return -1;
答案 2 :(得分:4)
让cost
成为下一站费用的数组,gas
是我们可以补充多少燃料的数组
我们计算gas[i]
和cost[i]
之间的差异,称为diff
,其中i是我们当前的加油站。
如果cost[i] > gas[i]
(或diff < 0
),则意味着我们需要至少cost[i] - gas[i]
燃油到达火车站i才能到达下一站,i + 1。 cost[i] <= gas[i]
(diff >= 0
),这是一个有效的起点,因为我们可以在没有气体的情况下开始,填满并前往下一站。在最坏的情况下,我们将使用空罐到达下一站。充其量,当我们达到i + 1(diff > 0
)
我们实际上不必从一个站开始,成功遍历n个加油站以查明是否有有效的旅行!只要总和燃料&gt; =总成本,就会有一个有效的旅游。所以我们只需要对数组进行O(n)传递
更多分析:
案例1:坦克跌破0
这只会发生在diff < 0
的停靠点。之后可能还有另一个起点,它在经过一轮通过该站后收集足够多的燃料。但是,我们之前通过的所有站点都没有用,所以我们不需要考虑它们(看案例2的解释)。
案例2:Tank目前&gt; = 0,但我们遇到另一个有效的起点
我们可以放心地忽略这一点,因为:
A - B - C.如果B可以达到C,A可以达到B,则A可以达到C.
案例3:Tank目前&gt; = 0,不是有效的起点
继续前进到下一个
案例4:管理到达原始起点!
耶!
def find_starting_station(gas, cost):
sum_gas = sum_cost = tank = start = 0
for i in range(0, len(gas)):
sum_gas += gas[i]
sum_cost += cost[i]
tank += gas[i] - cost[i]
if tank < 0:
tank = 0
start = i+1
if sum_gas < sum_cost:
return -1
return start
答案 3 :(得分:1)
这基本上是最大的子阵列总和问题。另一方面,我们可以从不同的POV来看待它。如果我们从第一个加油站开始旅程,让我们找出燃料最不足的地方。由于我们知道到达这一点应该占用大部分燃料,我们可以得出结论,卡车必须从这一点开始,以尽量减少负的燃料平衡。 下面是具有O(N)时间和O(1)空间复杂度的驱动程序的解决方案,并且不需要任何DP,因为一切都在一次通过中完成,并且仅使用两个整数来存储起点索引和它的价值(虽然这仅用于印刷目的)。
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <vector>
#include <algorithm>
using namespace std;
int gasoline[] = {8, 6, 30, 9, 15, 21, 2, 18};
int stations[] = {15, 8, 2, 6, 18, 9, 21, 30};
int rnd_num(const int& low, const int& high)
{
int rndnum = (int) (((double) rand() / (double) RAND_MAX) * (high - low + 1) + low);
return rndnum;
}
void swap(int data[], const int& idxlow, const int& idxhigh)
{
int tmp = data[idxlow];
data[idxlow] = data[idxhigh];
data[idxhigh] = tmp;
}
void print_array(const char* label, int data[], int size)
{
printf("%-10s: ", label);
for (int i = 0; i < size; ++i){
printf("%-3d ", data[i]);
}
printf("\n");
}
void print_vector(const char* label, const vector<int>& data)
{
printf("%-10s: ", label);
for (vector<int>::size_type i = 0; i < data.size(); ++i){
printf("%-3d ", data[i]);
}
printf("\n");
}
void shuffle(int data[], int size)
{
for (int i = 0; i < size - 1; ++i){
int idx = rnd_num(i + 1, size - 1);
swap(data, i, idx);
}
}
void run(int gas[], int dist[], int size)
{
vector<int> path;
int diff = 0, vidx, minidx = 0, minval = gas[0] - dist[0];
path.resize(size);
for (int i = 0; i < size; ++i) {
diff += gas[i] - dist[i];
if (i == size - 1){
vidx = 0; //path[0] = diff;
}
else {
vidx = i + 1; //path[i + 1] = diff;
}
path[vidx] = diff;
if (diff < minval) {
minval = diff;
minidx = vidx;
}
}
print_vector("PATHS ", path);
printf("MINIDX: %d\nMINVAL: %d\n", minidx, minval);
}
int main()
{
int size = sizeof(stations)/sizeof(stations[0]);
srand((unsigned)time(NULL));
shuffle(gasoline, sizeof(gasoline)/sizeof(gasoline[0]));
shuffle(stations, sizeof(stations)/sizeof(stations[0]));
print_array("GASOLINE ", gasoline, sizeof(gasoline)/sizeof(gasoline[0]));
print_array("STATIONS ", stations, sizeof(stations)/sizeof(stations[0]));
run(gasoline, stations, size);
return 0;
}
答案 4 :(得分:0)
从任何一个站点开始,尝试移动到下一个站点(右侧)。如果你不能(用完汽油),我们必须从起点左侧取气(将起动站移到左侧)。
start = 0
end = start
amount = 0
for i in range(n):
if amount > 0:
amount += (gas[end] - cost[end])
end = (end + 1) % n
else:
start = (start - 1 + n) % n
amount += (gas[start] - cost[start])
if amount >= 0: return start
return -1
`
答案 5 :(得分:0)
这是我在python中的解决方案。除了其他解释,一旦我们保留一个变量来计算前一站的需要,当我们在阵列的末尾时,我们只检查我们的剩余物是否高于该需要并相应地返回。
if not gas or not cost:
return - 1
index = 0
start = 0
total = 0
need = 0
while index < len(gas):
# If we can travel without any leftover.
# What is our status since start, if total is
# below zero that means we are in a worse situation
# then we were.
total += gas[index] - cost[index]
if total < 0 :
need -= total
start = index + 1
total = 0
index += 1
if total - need >= 0:
return start
else:
return -1
答案 6 :(得分:0)
此问题的解决方案基于贪婪算法。它基于以下两个观察结果。
如果总气体>成本,必须有一个开始指数来完成圆圈,否则就没有了;
- 醇>
对于索引i,如果来自i,j是我们无法达到的第一个索引,那么从i到j的任何索引都不能是起始索引。
有关详细说明,请查看以下链接 - Gas Station problem.
答案 7 :(得分:0)
我们得到2个数组,一个数组表示双层Bi上可用的气体量,另一个数组表示我们花费从i到i + 1的气体量。 我们尝试从第一个掩体开始,并假设它是解决方案。甚至当我们看到仓中的残余气体+可用气体<需要的气体量时,我们将解决方案重置为下一个指标,重复该过程,直到达到起始点(我们最后假定的解决方案)
public int getStationIndex() {
int answer = -1;
if (gasAvailableArray.length != gasExpenditureArray.length) {
throw new IllegalArgumentException("Invalid input array provided");
}
Queue<Integer> queue = new ArrayDeque<>();
int residue = 0;
for (int index = 0; ; ) {
if (index >= gasAvailableArray.length) {
index = index % (gasAvailableArray.length - 1);
}
if (index == answer) {
return answer;
}
if (residue + gasAvailableArray[index] - gasExpenditureArray[index] >= 0) {
// Only set a new answer when we had a reset in last iteration
if (answer == -1) {
answer = index;
}
residue += gasAvailableArray[index] - gasExpenditureArray[index];
queue.add(index);
} else {
while (!queue.isEmpty()) {
queue.poll();
}
}
answer = -1;
index++;
}
}
答案 8 :(得分:0)
static int findIndex(int A[], int B[]) {
int N = A.length;
int start=0;
boolean isBreak=false;
int total = 0;
do {
for(int i=start;i<start+A.length;i++) {
int c = A[i%N] - B[i%N];
total +=c;
if(total < 0) {
total= 0;
isBreak=true;
break;
}
}
if(isBreak) {
start++;
isBreak=false;
} else {
return start;
}
} while(start < A.length);
return -1;
}
答案 9 :(得分:0)
static int find(int A[], int B[]) {
for (int start = 0; start < A.length; start++) {
int x = findIndex(A, B, start);
if (x != -1)
return x;
}
return -1;
}
static int findIndex(int A[], int B[], int start) {
int total=0;
int N = A.length;
for (int i = start; i < start + A.length; i++) {
int c = A[i % N] - B[i % N];
total += c;
if (total < 0) {
total = 0;
return -1;
}
}
return start;
}
测试用例:
A : { 1, 2, 3, 4, 5 }, B : { 1, 3, 2, 4, 5 }
->索引2
A : {2,2,1}, B : {2,1,2}
索引-> 0
A : {1,2}, B {2,1}
->索引1
A : {1,2,1}, B {2,1,3}
->索引-1
答案 10 :(得分:0)
static int getIndex(int A[], int B[]) {
int start = -1;
int N = A.length;
for (int i = 0; i < N; i++) {
int c = A[i] - B[i];
if (c >= 0) {
int j = i + 1;
while (c >= 0 && j < i + N) {
c += A[j % N] - B[j % N];
j++;
}
if (c >= 0) {
start = i;
break;
}
}
}
return start;
}