В старых играх с двумерной
графикой можно столкнуться с подобной ситуацией. Какой-нибудь
герой прыгает по платформам (или островкам), которые висят в воздухе. Он
должен перебраться с одного края экрана до другого. Игрок может прыгнуть с
любой платформы i на любую
платформу k, затратив при этом (i – k)2 * (yi – yk)2 единиц
энергии, где yi и yk – высоты на которых
расположены эти платформы. Конечно же, энергию следует расходовать максимально
экономно.
Предположим, что вам известны
координаты всех платформ в порядке от левого края до правого. Сможете ли вы
найти, какое минимальное количество энергии потребуется герою, чтобы добраться
с первой платформы до последней?
Вход. В
первой строке записано количество платформ n (1 ≤ n ≤ 4000). Вторая строка
содержит n целых чисел, не превосходящих по
модулю 200000 – высоты, на которых располагаются платформы.
Выход. Выведите
единственное число – минимальное количество энергии, которое должен потратить
игрок на преодоление платформ.
Пример
входа |
Пример
выхода |
4 1 2 3 30 |
731 |
графы –
алгоритм Дейкстры
Анализ алгоритма
Рассмотрим
каждую платформу как вершину графа. Между каждой парой вершин i и j проведем неориентированное
ребро g[i][j]
весом
(i – j)2 * (yi – yj)2 (количество энергии, необходимое для перемещения
между вершинами i и j). Далее следует найти минимальный путь между первой и последней вершиной, что
можно совершить при помощи алгоритма Дейкстры.
Граф в памяти держать нет
необходимости, так как все значения g[i][j] при вычислениях пересчитываются по выше
указанной формуле.
Пример
Граф и его
весовая матрица имеют вид:
Герою следует
передвигаться по платформам в порядке 1 → 2 → 3 → 4, на что
следует потратить 1 + 1 + 729 = 731 единиц энергии.
Реализация алгоритма
Определим константы:
·
MAX – количество платформ;
·
INF – максимальное число типа kong long;
#define MAX 4001
#define INF
0x3F3F3F3F3F3F3F3FLL
Объявим рабочие массивы:
int used[MAX];
long long m[MAX], dist[MAX];
Читаем входные данные – высоты платформ. Платформы нумеруются
с 0 до n – 1.
scanf("%d", &n);
for (i = 0; i < n; i++)
scanf("%lld",
&m[i]);
Инициализируем массив кратчайших расстояний dist.
memset(dist, 0x3F, sizeof(dist));
dist[0] =
0;
Запускаем алгоритм Дейкстры из 0 вершины.
for (i = 1; i < n; i++)
{
min =
INF; w = -1;
for (j =
0; j < n; j++)
if
(!used[j] && dist[j] < min) { min = dist[j]; w = j; }
if (w
< 0) break;
for (j =
0; j < n; j++)
{
Вычисляем расстояние len между вершинами w и j.
long long len = (w - j)
* (w - j) * (m[j] - m[w]) * (m[j] - m[w]);
Если кратчайшее расстояние до вершины j еще не вычислено, то релаксируем ребро (w, j).
if
(!used[j] && dist[j] > dist[w]
+ len) dist[j] = dist[w] + len;
}
used[w]
= 1;
}
Выводим кратчайшее расстояние до вершины n – 1.
printf("%lld\n", dist[n - 1]);
printf("%lld\n", dist[n - 1]);
import java.util.*;
public class Main
{
static int used[];
static long m[], dist[];
static long INF = 1000000000000000000L;
public static void main(String[] args)
{
Scanner con = new
Scanner(System.in);
int n = con.nextInt();
m = new long[n];
for (int i = 0; i < n; i++)
m[i] = con.nextLong();
used = new int[n];
dist = new long[n];
Arrays.fill(dist, INF);
dist[0] = 0;
for (int i = 1; i < n; i++)
{
long min = INF;
int w = -1;
for (int j = 0; j < n; j++)
if (used[j] == 0 && dist[j] < min) { min = dist[j]; w = j; }
if (w < 0) break;
for (int j = 0; j < n; j++)
{
long len = (w - j) * (w - j) * (m[j] - m[w]) * (m[j] - m[w]);
if (used[j] == 0 && dist[j] > dist[w] + len)
dist[j] = dist[w] + len;
}
used[w] = 1;
}
System.out.println(dist[n-1]);
con.close();
}
}