Хорошо, мне нужно подтолкнуть в правильном направлении. У меня есть целый ряд расходов на поездку из города от 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;
}
То, что вы хотите сделать, - это выбрать полеты на максимум K
маршрутах, где это даст самое большое улучшение (и, очевидно, больше не выбирайте, если их больше нет, что приведет к улучшению).
Итак, в вашем примере:
roadTime = { 1, 2, 3};
flightTime = { 2, 1, 6};
improvement -1 1 -3
Второй, который показывает улучшение (и, следовательно, самое большое улучшение), является вторым, поэтому мы выбираем рейс для этого.
Подсказка - приоритетная очередь может помочь. Графов не требуется.
На всякий случай, я хотел бы предложить подход к динамическому программированию как видение вашей проблемы.
Предположим, что у нас есть функция, которая определяет стоимость доставки в город, имея некоторое количество разрешенных попыток полета (и неограниченные попытки дороги).
Таким образом, стоимость добраться до какого-то города зависит от стоимости перехода на предыдущий город и количества разрешенных полетных попыток:
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];
}
}