Возле вилы
Пемберлей в южном районе Байтерляндии находится большое пастбище. Миссис Дарси
беспокоится за свои нежные растения, которые могут быть вытоптаны незнакомцами.
Поэтому она решила на пастбище окружить треугольным забором некоторые участки
земли.
В подвале у
миссис Дарси есть несколько оград для забора. Для ограничения одной треугольной
области она может использовать только три ограды. То есть каждая сторона
образованного треугольника представляет собой только одну имеющуюся в наличии
ограду. Ограды достаточно красивы, поэтому она решила не склеивать несколько
оград для получения одной стороны, а также не разрезать одну ограду на
несколько меньших. Задача миссис Дарси - ограничить забором как можно большую
площадь пастбища.
Вход. Каждая строка является отдельным тестом. Первое число
строки содержит количество оград n (n ≤ 16), имеющихся у миссис Дарси.
Следующие n целых чисел в промежутке
от 1 до 100 описывают длины этих оград.
Выход. Для каждого теста в отдельной строке выведите
максимальную площадь, которую можно оградить имеющимися кусками забора. Ответ
следует выводить с 4 десятичными знаками.
Пример входа |
Пример выхода |
7 3 4 5 6 7 8 9 4 1 2 4 8 4 7 4 4 4 |
36.7544 0.0000 6.9282 |
РЕШЕНИЕ
динамическое программирование - маски
Анализ алгоритма
Площадь треугольника со сторонами a, b, c ищем в функции area(a, b,
c) по формуле Герона:
S = , где p =
Пусть P – некоторое подмножество имеющихся кусков забора.
Функция FindSol(mask) будет находить максимальную площадь, которую можно
оградить при помощи них треугольными формами. Переменная mask содержит маску подмножества: она является 16-битовым числом, i-ый бит которого равен 1, если подмножество P содержит кусок fences[i], и 0
иначе. Ответом на задачу в таком случае будет значение FindSol(2n – 1), где n – количество чисел в массиве fences.
Значения всевозможных масок mask лежит в промежутке от 0 до 216 – 1 (по условию имеются
не более 16 кусков забора). В ячейке best[mask]
храним максимальную площадь, которую можно оградить подмножеством кусков
изгороди, описывающим маской mask.
Для вычисления FindSol(mask)
следует перебрать все возможные тройки кусков забора i, j, k, присутствующих в mask, проверить для них неравенство треугольника (можно ли из них
составить треугольник) и найти сумму
area(fences[i],
fences[j], fences[k]) + FindSol(mask \ {i, j, k})
Перебираем все тройки (i,
j, k) и находим такую, для которой указанная сумма максимальна. Ее
значение присваиваем ячейке best[mask].
FindSol(mask) =
Если изначально
длины кусков забора отсортировать, то при проверке неравенства треугольника
(стороны которого равны fences[i],
fences[j], fences[k]), достаточно проверить только одно
условие:
fences[i] + fences[j] > fences[k],
так как из
неравенства fences[i] £ fences[j] £ fences[k]
всегда сдедует, что fences[i] +
fences[k] > fences[j] и fences[j] + fences[k] >
fences[i].
Реализация алгоритма
Объявим глобальные переменные.
#define MAX 16
double best[1<<MAX];
int f[MAX+1];
Функция area вычисляет
площадь треугольника по формуле Герона.
double area(int a, int b, int c)
{
double p = (a + b + c) / 2.0;
return sqrt(p * (p-a) * (p-b) * (p-c));
}
Функция FindSol
возвращает максимальную площадь, которую можно оградить при помощи оград,
входящих в маску mask, треугольными
формами.
double FindSol(int mask)
{
if (best[mask] >= 0.0) return
best[mask];
best[mask] = 0;
for(int i = 0; i <
n - 2; i++) if (mask & (1 << i))
for(int j = i + 1; j
< n - 1; j++) if (mask & (1 << j))
for(int k = j + 1; k
< n; k++) if (mask & (1 << k))
if (f[i] + f[j] > f[k]) best[mask] =
max(best[mask],
area(f[i],f[j],f[k]) +
FindSol(mask ^ (1 << i) ^ (1
<< j) ^ (1 << k)));
return best[mask];
}
Основная часть
программы. После считывания длин оград сортируем их по неубыванию.
while(scanf("%d",&n)
== 1)
{
memset(f,0,sizeof(f));
for(i = 0; i < n; i++) scanf("%d",&f[i]);
sort(f,f+n);
for(i = 0; i < (1 << MAX); i++) best[i] =
-1.0;
printf("%.4lf\n",FindSol((1 << n) - 1));
}