Нехай — даний набір паличок. Необхідно знайти два непересічних підмножини і з , такі, щоб палички кожного з них можна було розбити на дві підмножини з рівною сумою довжин.
Для кожного підмножини mask \subseteq S обчислимо суму довжин його паличок і запишемо в sum[mask].
Переберемо всі підмножини I \subset S. Для кожної підмножини переберемо всі його підмножини J \subset I. Якщо існує таке , що 2 \cdot sum[J] = sum[I] (тобто сумарна довжина паличок в вдвічі менша від суми довжин усіх паличок з ), то підмножина можна використовувати в якості протилежних сторін прямокутника. У цьому випадку встановимо can[I] = true.
Вся описана процедура виконується за O(3^n).
Переберемо всі підмножини множини паличок. Якщо для деякого множини існує підмножина J \subset I таке, що can[J] = true і can[I~xor~J] = true (тобто множини і I~xor~J не перетинаються), то тим самим отримуємо один з можливих розподілів паличок між горизонтальними і вертикальними сторонами прямокутника.
Довжини сторін такого прямокутника дорівнюють sum[J] / 2 і sum[I~xor~J] / 2. Серед усіх знайдених варіантів обираємо прямокутник з максимальною площею.
Реалізація алгоритму
Довжини паличок зберігаються в масиві . Для кожного підмножини паличок зберігаємо їхню сумарну довжину в масиві sum[mask]. Значення can[mask] встановлюємо в , якщо множина можна поділити на дві підмножини з рівною сумою довжин, які відповідатимуть протилежним сторонам прямокутника.
#define MAX 16
int a[MAX];
int sum[1 << MAX];
bool can[1 << MAX];Основна частина програми. Читаємо вхідні дані.
scanf("%d",&n);
for (i = 0; i < n; i++)
scanf("%d", &a[i]);Переберемо всі підмножини паличок і обчислимо сумарну довжину кожного з них.
for (i = 0; i < 1 << n; i++)
for (j = 0; j < n; j++)
if (i & (1 << j)) sum[i] += a[j];Далі переберемо всі можливі підмножини множини паличок. Якщо для деякого множини існує підмножина J \subset I таке, що сумарна довжина паличок в вдвічі менша сумарної довжини паличок в , то встановимо can[I] = true. У цьому випадку палички з множини можна використовувати як протилежні сторони прямокутника.
for (i = 1; i < 1 << n; i++)
{
int s = sum[i];
for (j = i; j > 0; j = (j - 1) & i)
if (sum[j] * 2 == s)
{
can[i] = true;
break;
}
}Переберемо всі підмножини множини паличок. Якщо для деякого множини існує підмножина J \subset I таке, що can[J] = true і can[I~xor~J] = true, то отримуємо один з можливих розподілів паличок між горизонтальними і вертикальними сторонами прямокутника. Довжини сторін такого прямокутника дорівнюють sum[J] / 2 і sum[I xor J] / 2.
res = 0;
for (i = 1; i < 1 << n; i++)
for (j = i; j > 0; j = (j - 1) & i)
if (can[j] && can[i ^ j])
res = max(res, sum[j] / 2 * 1LL * sum[i ^ j] / 2);Виводимо площу знайденого прямокутника максимального розміру.
printf("%lld\n",res);