Как бы вы смотрели на разработку алгоритма для этой проблемы отеля?
Есть проблема, над которой я работаю, для курса программирования, и у меня возникла проблема с разработкой алгоритма для решения этой проблемы. Вот он:
Вы отправитесь в долгий путь. Вы начинаете на дороге в миле. 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 в динамическом программировании без вложенных циклов.
Мы начинаем с нуля миль.
Мы находим следующую остановку, удерживая штраф как можно ниже, сравнивая штраф текущего отеля в цикле с предыдущим штрафом отеля.
Как только у нас будет наш текущий минимум, мы нашли нашу остановку на день. Мы назначаем эту точку в качестве нашей следующей отправной точки.
При желании мы можем сохранить общее количество штрафов:
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)