Кратчайший путь от города 0 до N (автомобильным / воздушным смешанным тарифом)

1

Хорошо, мне нужно подтолкнуть в правильном направлении. У меня есть целый ряд расходов на поездку из города от 0 до N и целый ряд расходов на перелет из города от 0 до N на рейс. У меня есть предел K по количеству рейсов, которые я могу совершить во время поездок. Например

N = 3 // there are 3 cities to be visited 0->1 ->2 ->3 in consecutive order
roadTime = { 1, 2, 3};
flightTime = { 2, 1, 6};
K = 2; //take a maximum of 2 flights

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

То, что я пробовал:

Начав вручную, пытаясь найти возможное решение и придумал бинарное дерево, но не смог представить древовидную структуру кода (С#), не вытаскивая мои волосы, я слишком новичок в графиках, чтобы даже думать о применении их. Но в процессе работы над этим я затем наткнулся на идею и, думая, что я прибил ее, я понял, что могу найти перестановки в поездке от 0 до N с сочетанием стоимости дороги и стоимости полета, чтобы получить минимум Стоимость:

public int minTime(int N, int[] roadTime, int[] flightTime, int K)
    {
        int n = 0;
        int min = roadTime.Sum();
        while (K > 0)
        {
            char[] s = (new string('A', N - K) + new string('B', K)).ToCharArray();
            do
            {
                n = 0;
                for (int i = 0; i < s.Length; i++)
                {
                    if (s[i] == 'A')
                    {
                        n += roadTime[i];
                    }
                    else
                    {
                        n += flightTime[i];
                    }
                }
                min = (n < min) ? n : min;
            } while (permute(s));
            K--;
        }
        return min;
    }
    public Boolean permute(char[] a)
    {
        int N = a.Length, i = N - 2;
        for (; i >= 0; i--)
            if (a[i] < a[i + 1])
                break;
        if (i < 0) return false;

        for (int j = N - 1; j >= i; j--)
        {
            if (a[j] > a[i])
            {
                var temp = a[i];
                a[i] = a[j];
                a[j] = temp;
                break;
            }
        }
        for (int j = i + 1; j < (N + i + 1) / 2; j++)         
        {
            var temp = a[j];
            a[j] = a[N + i - j];
            a[N + i - j] = temp;
        }
        return true;

    }

Это работает нормально, но естественно, что N → 12, есть факторный рост числа перестановок издержек. Мое решение работает до 15 городов в разумные сроки. Мне нужно найти способ решить эту проблему, чтобы я мог найти минимальную стоимость для 1 не менее 50 городов.

Даже думая об этом интуитивно, как вы можете быть уверены, что у вас есть хоть что-то, если вы не пробовали их всех?

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

Любая помощь приветствуется.

РЕДАКТИРОВАТЬ!!! 18/май /2014:

Нашел ответ после толчка в правильном направлении от Дукелинга. Надеюсь, что кто-то найдет это полезное

public int minTime(int N, int[] roadTime, int[] flightTime, int K)
    {
        int n = 0;
        int min = roadTime.Sum();
        do
        {
            n = 0;
            var sortedDict = (from entry in cost(roadTime, flightTime, N)
                              orderby entry.Value descending
                              where entry.Value > 0 select entry 
                  ).Take(K)
                  .ToDictionary(pair => pair.Key, pair => pair.Value);

            for (int i = 0; i < N; i++)
            {
                if (sortedDict.ContainsKey(i))
                {
                    n += flightTime[i];
                }
                else
                {
                    n += roadTime[i];
                }
            }
            min = (n < min) ? n : min;
            K--;
        } while (K > 0);

        return min;
    }
    static Dictionary<int, int> cost (int[] a1, int[] a2, int N)
    {
        Dictionary<int, int> d = new Dictionary<int, int>();
        for(int i = 0; i < N; i++)
        {
            d.Add(i, a1[i] - a2[i]);
        }
        return d;
    }
Теги:
algorithm

2 ответа

2
Лучший ответ

То, что вы хотите сделать, - это выбрать полеты на максимум K маршрутах, где это даст самое большое улучшение (и, очевидно, больше не выбирайте, если их больше нет, что приведет к улучшению).

Итак, в вашем примере:

roadTime   = { 1, 2, 3};
flightTime = { 2, 1, 6};
improvement    -1 1  -3

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

Подсказка - приоритетная очередь может помочь. Графов не требуется.

  • 0
    Выглядит хорошо, но я думаю, что логика может быть назад к фронту. Вероятно, ему следует лететь только за вторым, чтобы дать самое короткое общее время 1 + 1 + 3 = 5.
  • 0
    @PeterdeRivaz Ах, да, спасибо. Я не уделял достаточно внимания.
Показать ещё 1 комментарий
0

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

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

Таким образом, стоимость добраться до какого-то города зависит от стоимости перехода на предыдущий город и количества разрешенных полетных попыток:

Cost(cityNum, flyAttempts) = 
    min(
       Cost(cityNum - 1, flyAttempts)    + roadTimeTo[cityNum], // moving by road
       Cost(cityNum - 1, flyAttempts - 1) + flyTimeTo[cityNum], // moving by fly
    );

Основой динамического программирования является:

1) Cost of getting to the starting city: 
Cost[0, n] = 0 // n - is any number

2) Cost of getting to any city, when there are no fly attempts: 
Cost[n, 0] = Cost[n - 1, 0] + roadCost[n] // n - is any number

Мы можем использовать динамическое программирование "снизу вверх", чтобы решить вашу проблему (я дам действительное решение Java):

public class Fly {

    public static void main(String[] args) {
        int citiesNum = 4;
        int flyAttempts = 2;
        int[] roadCost = new int[] { 1, 2, 3 };
        int[] flyCost = new int[] { 2, 1, 6 };

        int shortestWay =
                shortestWay(roadCost, flyCost, citiesNum, flyAttempts);

        System.out.println(shortestWay);
    }

    public static int shortestWay(
            int[] roadCost,
            int[] flyCost,
            int citiesNum,
            int flyAttempts) {

        // Cost matrix
        int[][] cost = new int[citiesNum][flyAttempts + 1];

        int lastCity = citiesNum - 1;

        // Initializing base conditions of Dynamic Programming
        for (int i = 0; i <= flyAttempts; i++) {
            cost[0][i] = 0;
        }
        for (int i = 1; i <= lastCity; i++) {
            cost[i][0] = cost[i - 1][0] + roadCost[i - 1];
        }

        // Calculating cost matrix
        for (int i = 1; i <= lastCity; i++) {
            for (int j = 1; j <= flyAttempts; j++) {
                cost[i][j] = Math.min(
                        cost[i - 1][j] + roadCost[i - 1],
                        cost[i - 1][j - 1] + flyCost[i - 1]);
            }
        }

        return cost[lastCity][flyAttempts];
    }
}
  • 0
    Это работает намного быстрее, чем мой код и использует примерно 1/3 меньше памяти, хорошая работа. Тем не менее, все еще оборачиваясь вокруг производной функции.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню