Как бы вы посмотрели на разработку алгоритма для этой проблемы отеля? - PullRequest
15 голосов
/ 10 февраля 2011

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

Вы отправляетесь в долгое путешествие. Вы начинаете на дороге в 0 миль. По пути есть н отели, на милевых постах a1

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

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

Ответы [ 9 ]

9 голосов
/ 10 февраля 2011

Если 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.

edit : переключился на код 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 
6 голосов
/ 10 февраля 2011

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

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 голосов
/ 10 февраля 2011

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

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

1 голос
/ 28 апреля 2017

Шаг 1 из 2

Sub-проблема:

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

Алгоритм нахождения минимального общего штрафа:

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

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

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

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

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

псевдокод:

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

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

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

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

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

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

C (j) = мин (C (i), C (i) + (200 - (aj - ai)) ^ 2}

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

возврат C (n)

Шаг 2 из 2

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

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

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

Этот алгоритм содержит «n» подзадач, и для каждой подзадачи требуется «O (n)» раз.

  • Требуется вычислить только минимальные значения «O (n)».

  • И процесс возврата занимает «O (n)» раз.

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

Поэтому для полного решения этого алгоритма требуется «0 (n ^ 2)» раз.

1 голос
/ 16 июля 2016

Ниже приведен код 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
1 голос
/ 10 февраля 2011

Я не думаю, что вы можете сделать это так легко, как утверждает 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 от
    current и Penalty> current.penalty, удалите егоиз списка
  • петля
0 голосов
/ 12 сентября 2018

Недавно я столкнулся с этой проблемой и хотел поделиться своим решением, написанным на 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 []
0 голосов
/ 25 октября 2013

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

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

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

P (i) = min {P (j) + (200 - (D (ai) - D (dj)) ^ 2}, где j равно: 0 <= j <i </em>

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

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

0 голосов
/ 10 февраля 2011

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...