Как бы вы смотрели на разработку алгоритма для этой проблемы отеля?

Есть проблема, над которой я работаю, для курса программирования, и у меня возникла проблема с разработкой алгоритма для решения этой проблемы. Вот он:

Вы отправитесь в долгий путь. Вы начинаете на дороге в миле. 0. По пути есть n гостиниц, в милях сообщений a1 < a2 <... < a, где каждый ai измеряется от начальной точки. в этих отелях есть только те места, где вы можете остановиться, но вы можете выбрать, какие из отелей вы останавливаетесь. Вы должны остановиться в конечном отеле (на расстоянии a), который является вашим пунктом назначения. Вы идеально хотели бы путешествовать 200 миль в день, но это может быть невозможно (в зависимости от расстояния гостиниц). Если вы путешествуете на x миль в течение дня, штраф за этот день составляет (200 - x) ^ 2. Вы хотите планировать свою поездку таким образом, чтобы свести к минимуму общее наказание, то есть сумму, в течение всех дней путешествия, суточные штрафы. Дайте эффективный алгоритм, который определяет оптимальную последовательность отелей, на которых останавливаться.

Итак, моя интуиция подсказывает мне начинать со спины, проверять значения штрафа, а затем как-то сопоставлять их с возвратом вперед (в результате получается время выполнения O (n ^ 2), которое достаточно оптимально для ситуации).

Кто-нибудь видит какой-либо возможный способ выработать эту идею или какие-либо идеи о возможных имплантациях?

Ответы

Ответ 1

Если x - номер маркера, ax - пробег к этому маркеру, а px - минимальное наказание, чтобы добраться до этого маркера, вы можете рассчитать pn для маркера n, если знаете pm для всех маркеров m до n.

Чтобы вычислить pn, найдите минимум pm + (200 - (an - am))^2 для всех маркеров m, где am < an и (200 - (an - am))^2 меньше вашего текущего наилучшего для pn (последняя часть - это оптимизация).

Для стартового маркера 0, a0 = 0 и p0 = 0 для маркера 1, p1 = (200 - a1)^2. С этой начальной информацией вы можете вычислить p2, затем p3 и т.д. До pn.

изменить. Переключить на Java-код, используя пример из комментария OP. Обратите внимание, что это не имеет проверки оптимизации, описанной во втором абзаце.

public static void printPath(int path[], int i) {
    if (i == 0) return;
    printPath(path, path[i]);
    System.out.print(i + " ");
}

public static void main(String args[]) {
    int hotelList[] = {0, 200, 400, 600, 601};
    int penalties[] = {0, (int)Math.pow(200 - hotelList[1], 2), -1, -1, -1};
    int path[] = {0, 0, -1, -1, -1};
    for (int i = 2; i <= hotelList.length - 1; i++) {
        for(int j = 0; j < i; j++){
            int tempPen = (int)(penalties[j] + Math.pow(200 - (hotelList[i] - hotelList[j]), 2));
            if(penalties[i] == -1 || tempPen < penalties[i]){
                penalties[i] = tempPen;
                path[i] = j;
            }
        }
    }
    for (int i = 1; i < hotelList.length; i++) {
        System.out.print("Hotel: " + hotelList[i] + ", penalty: " + penalties[i] + ", path: ");
        printPath(path, i);
        System.out.println();
    }
}

Выход:

Hotel: 200, penalty: 0, path: 1 
Hotel: 400, penalty: 0, path: 1 2 
Hotel: 600, penalty: 0, path: 1 2 3 
Hotel: 601, penalty: 1, path: 1 2 4 

Ответ 2

Похоже, вы можете решить эту проблему с помощью динамического программирования. Подзадача следующая:

d(i): минимальный штраф возможен при путешествии от начала до отеля i.

Рекурсивная формула выглядит следующим образом:

d(0) = 0 где 0 - начальная позиция.

d(i) = min_{j=0, 1, ... , i-1} ( d(j) + (200-(ai-aj))^2)

Минимальный штраф за достижение отеля i можно найти, попробовав все места остановки за предыдущий день, добавив сегодня штраф и взяв минимум.

Чтобы найти путь, мы храним в отдельном массиве (путь []), к которому мы должны были ехать, чтобы добиться минимального штрафа за этот отель. Перемещая массив назад (с пути [n]), мы получаем путь.

Время выполнения O (n ^ 2).

Ответ 3

Это эквивалентно поиску кратчайшего пути между двумя узлами в направленном ациклическом графе. Алгоритм Дейкстры будет работать в O (n ^ 2) времени.

Ваша интуиция лучше. Начиная со спины, рассчитайте минимальный штраф за остановку в этом отеле. Первый штраф в отеле - всего лишь (200- (200-x) ^ 2) ^ 2. Затем, для каждой из других гостиниц (в обратном порядке), отсканируйте вперед, чтобы найти гостиницу с самым низким штрафом. Простая оптимизация заключается в том, чтобы остановить, как только стоимость штрафа начнет увеличиваться, поскольку это означает, что вы превысили глобальный минимум.

Ответ 4

Я не думаю, что вы можете сделать это так же легко, как sysrqb.

На стороне примечания, нет никакой разницы, чтобы начать с начала или конца; цель состоит в том, чтобы найти минимальное количество остановок в каждом направлении, где каждая остановка максимально приближается к 200 м.

Вопрос, который, как утверждается, позволяет путешествовать за пределы 200 м в день, а штраф в равной степени действителен для более или менее (поскольку он равен квадрату). Это предпочитает превышение миль в день, а не несовершеннолетних, поскольку штраф равен, но цель ближе.

Однако, учитывая этот макет

A ----- B----C-------D------N
0       190  210     390    590

Это не всегда так. Лучше перейти к B- > D- > N для общего штрафа только за (200-190)^2 = 100. Дальнейшее продвижение через C- > D- > N дает штраф в размере 100+400=500.

Ответ выглядит как полный поиск по ширине с активной обрезкой, если у вас уже есть оптимальное решение для достижения точки P, удаляя все решения до сих пор, где

sum(penalty-x) > sum(penalty-p)  AND  distance-to-x <= distance-to-p - 200

Это был бы алгоритм O (n ^ 2)


Что-то вроде...
  • Отсортируйте все отели на расстоянии от начала (отбросьте все, что на расстоянии > hotelN)
  • Создайте массив/список решений, каждый из которых содержит (ListOfHotels, I, DistanceSoFar, Penalty)
  • Осмотрите каждый отель в порядке, для каждого hotel_I
      Вычислить штраф в I, начиная с каждого предыдущего решения.
  • Обрезка
      Для каждого предыдущего решения, которое превышает 200 distanceSoFar от
      текущий, и Penalty > current.penalty, удалите его из списка
  • цикл

Ответ 5

Ниже приведен код MATLAB для проблем с гостиницей.

clc
clear all

% Data     
% a = [0;50;180;150;50;40];    
% a = [0, 200, 400, 600, 601];    
  a = [0,10,180,350,450,600];    
% a = [0,1,2,3,201,202,203,403];

n = length(a);    
opt(1) = 0;    
prev(1)= 1;

for i=2:n
    opt(i) =Inf;
    for j = 1:i-1
        if(opt(i)>(opt(j)+ (200-a(i)+a(j))^2))
            opt(i)= opt(j)+ (200-a(i)+a(j))^2;
            prev(i) = j; 
        end
    end
    S(i) = opt(i);
end

k = 1;
i = n;
sol(1) = n;

while(i>1)
   k = k+1;
   sol(k)=prev(i);
   i = prev(i);   
end

for i =k:-1:1
    stops(i) = sol(i);
end
stops

Ответ 6

Шаг 1 из 2

Sub-проблема:

В этом случае "C (j)" считается субатомной проблемой для минимального штрафа, полученного до гостиницы "ai" , когда "0 <= я <= n". Требуемое значение для проблемы - "C (n)" .

Алгоритм для поиска минимального общего штрафа:

Если поездка остановлена ​​в месте "aj", тогда предыдущая остановка будет "ai" , а значение я и должно быть меньше j. Тогда все возможности "ai" были следующими:

C (j) min {C (i) + (200- (aj-ai)) ^ 2}, 0 <= я <= j.

  • Инициализируйте значение "C (0)" как "0" и "a0" как "0" , чтобы найти оставшиеся значения.

  • Чтобы найти оптимальный маршрут, увеличьте значение "j" и "i" для каждой итерации и используйте эту деталь для возврата из "C (n)" .

Здесь "C (n)" означает штраф последнего отеля (т.е. значение "i" находится между "0" и "n" ).

псевдокод:

//Определение функции

Процедура min_tot()

//Внешний цикл для представления значения для j = 1 - n:

//Рассчитаем расстояние каждой остановки C (j) = (200 - aj) ^ 2

//Внутренний цикл для представления значения для я = 1 - j-1:

//Вычислить суммарное наказание и назначить минимальный//общий штраф "С (к)"

C (j) = min (C (i), C (i) + (200 - (aj - ai)) ^ 2}

//Возвращает стоимость общего штрафа последнего отеля

return C (n)

Шаг 2 из 2

Объяснение: Вышеупомянутый алгоритм используется для определения минимального общего штрафа от начальной точки до конечной точки.

  • Он использует функцию "min()" для определения общего штрафа за каждую остановку в поездке и вычисляет минимум штрафное значение.

Время работы алгоритма:

Этот алгоритм содержит "n" подзадачи, и каждая подзадача принимает "O (n)" раз для решения.

  • Необходимо вычислить только минимальные значения "O (n)" .

  • И процесс обратного отслеживания принимает "O (n)" раз.

  • Общее время работы алгоритма: nxn = n ^ 2 = O (n ^ 2).

Следовательно, этот алгоритм полностью принимает "0 (n ^ 2)" раз для решения всей задачи.

Ответ 7

Чтобы ответить на ваш вопрос кратко, алгоритм PSPACE-complete обычно считается "эффективным" для большинства проблем ограничения соответствия, поэтому, если у вас есть алгоритм O (n ^ 2), этот "эффективный".

Я думаю, что самый простой метод, учитывая N полных миль и 200 миль в день, заключался бы в том, чтобы разделить N на 200, чтобы получить X; количество дней, в которые вы будете путешествовать. Разобьем это до ближайшего целого числа дней X ', затем разделим N на X', чтобы получить Y, оптимальное количество миль для путешествия за день. Это фактически постоянная работа. Если бы на каждом километре была гостиница, остановка в этих гостиницах обеспечивала бы наименьший возможный балл, минимизируя эффект квадратов штрафа за каждый день. Например, если общая поездка составляет 605 миль, штраф за проезд 201 миль в день (202 на последнем) равен 1 + 1 + 4 = 6, что намного меньше 0 + 0 + 25 = 25 (200 + 200 + 205), вы получите, минимизируя каждый индивидуальный штраф за проезд в день, когда вы пошли.

Теперь вы можете пройти список отелей. Самый быстрый способ состоял бы в том, чтобы просто выбрать отель, который ближе всего к каждому краю Y миль. Это линейное время и приведет к "хорошему" результату. Однако я не думаю, что это приведет к "лучшему" результату во всех случаях.

Более сложный, но надежный способ состоит в том, чтобы добраться до двух ближайших отелей до каждого кратного Y; тот, который был непосредственно перед этим, и тот, который сразу после. Это создает массив из X 'пар, который может быть пройден во всех возможных перестановках в 2 ^ X' времени. Вы можете сократить это, применив Dijkstra к карте этих пар, которая определит наименее дорогостоящий путь для каждого дневного путешествия и будет выполняться примерно (2X ') ^ 2 раза. Вероятно, это будет наиболее эффективный алгоритм, гарантирующий получение оптимального результата.

Ответ 8

Как упоминалось в @rmmh, вы находите минимальный путь расстояния. Здесь расстояние - штраф (200-x) ^ 2

Итак, вы попытаетесь найти план остановки, найдя минимальный штраф.

Допустим, что D (ai) дает расстояние от ai от начальной точки

P (i) = min {P (j) + (200 - (D (ai) - D (dj)) ^ 2}, где j: 0 <= j < i

Из случайного анализа это выглядит как

O (n ^ 2) алгоритм (= 1 + 2 + 3 + 4 +.... + n) = O (n ^ 2)

Ответ 9

Я недавно сталкивался с этой проблемой и хотел поделиться своим решением, написанным на Javascript.

Не отличаясь от большинства вышеупомянутых решений, я использовал подход динамического программирования. Чтобы рассчитать penalties[i], нам нужно найти такое место остановки за предыдущий день, чтобы штраф был минимальным. penalties(i) = min_{j=0, 1,..., i-1} ( penalties(j) + (200-(hotelList[i]-hotelList[j]))^2) Решение Не предполагайте, что первым штрафом является Math.pow(200 - hotelList[1], 2). Мы не знаем, оптимально ли останавливаться на первой вершине, поэтому не следует делать это предположение. Чтобы найти оптимальный путь и сохранить все остановки по пути, используется path вспомогательного массива. Наконец, массив перемещается в обратном направлении для вычисления finalPath.

function calculateOptimalRoute(hotelList) {
const path = [];
const penalties = [];

for (i = 0; i < hotelList.length; i++) {
    penalties[i] = Math.pow(200 - hotelList[i], 2)
    path[i] = 0
    for (j = 0; j < i; j++) {
        const temp = penalties[j] + Math.pow((200 - (hotelList[i] - hotelList[j])), 2)
        if (temp < penalties[i]) {
            penalties[i] = temp;
            path[i] = (j + 1);
        }

    }
}

const finalPath = [];
let index = path.length - 1

while (index >= 0) {
    finalPath.unshift(index + 1);
    index = path[index] - 1;
}
console.log('min penalty is ', penalties[hotelList.length - 1])
console.log('final path is ', finalPath)

return finalPath;

}

// calculateOptimalRoute([20, 40, 60, 940, 1500])
// Outputs [3, 4, 5]

// calculateOptimalRoute([190, 420, 550, 660, 670])
// Outputs [1, 2, 5]

// calculateOptimalRoute([200, 400, 600, 601])
// Outputs [1, 2, 4]

// calculateOptimalRoute([])
// Outputs []

Ответ 10

В качестве подтверждения концепции, вот мое решение JavaScript в динамическом программировании без вложенных циклов.

  1. Мы начинаем с нуля миль.

  2. Мы находим следующую остановку, удерживая штраф как можно ниже, сравнивая штраф текущего отеля в цикле с предыдущим штрафом отеля.

  3. Как только у нас будет наш текущий минимум, мы нашли нашу остановку на день. Мы назначаем эту точку в качестве нашей следующей отправной точки.

  4. При желании мы можем сохранить общее количество штрафов:

let hotels = [40, 80, 90, 200, 250, 450, 680, 710, 720, 950, 1000, 1080, 1200, 1480]

function findOptimalPath(arr) {
    let start = 0
    let stops = []
    for (let i = 0; i < arr.length; i++) {
        if (Math.pow((start + 200) - arr[i-1], 2) < Math.pow((start + 200) - arr[i], 2)) {
        stops.push(arr[i-1])
        start = arr[i-1]
    }
  }
  console.log(stops)
}
findOptimalPath(hotels)