Tutaq ki, verilmiş çubuqlar çoxluğudur. Lazımdır ki, çoxluğunun içərisindən iki kəsişməyən altçoxluq və tapaq ki, onların hər biri uzunluqları bərabər olan iki altçoxluğa bölünsün.
Hər altçoxluq üçün mask \subseteq S onun çubuqlarının uzunluqlarının cəmini hesablayıb sum[mask]-də qeyd edək.
Bütün altçoxluqları I \subset S olaraq seçək. Hər bir altçoxluq üçün onun bütün altçoxluqlarını J \subset I olaraq seçək. Əgər elə bir varsa ki, 2 \cdot sum[J] = sum[I] (yəni -dəki çubuqların ümumi uzunluğu -dəki bütün çubuqların uzunluqlarının cəminin yarısına bərabərdirsə), onda altçoxluq bir düzbucaqlının qarşı-qarşıya duran tərəfləri kimi istifadə edilə bilər. Bu halda can[I] = true təyin edək.
Təsvir olunan prosedur O(3^n) zamanda yerinə yetirilir.
Bütün çubuqlar çoxluqlarının altçoxluqlarını seçək. Əgər bir çoxluq üçün bir altçoxluq J \subset I varsa ki, can[J] = true və can[I~xor~J] = true (yəni və I~xor~J çoxluqları kəsişmir), onda bir düzbucaqlının üfüqi və şaquli tərəfləri arasında çubuqların bir mümkün düzülüşünü tapmış oluruq.
Belə bir düzbucaqlının tərəflərinin uzunluqları sum[J] / 2 və sum[I~xor~J] / 2 olur. Göstərilən dəyərlər arasında ən böyük sahəsi olan düzbucaqlını seçirik.
Alqoritmin icrası
Çubuqların uzunluqları massivində saxlanılır. Hər bir çubuqlar altçoxluğu üçün onların ümumi uzunluğunu sum[mask] massivində saxlayırıq. Əgər çoxluğu bərabər uzunluqlar cəmi olan iki altçoxluğa bölünə bilirsə - bu, düzbucaqlının qarşı-qarşıya duran tərəflərinə uyğun gələcək - can[mask] qiymətini olaraq təyin edirik.
#define MAX 16
int a[MAX];
int sum[1 << MAX];
bool can[1 << MAX];Proqramın əsas hissəsi. Daxil olan məlumatları oxuyuruq.
scanf("%d", &n);
for (i = 0; i < n; i++)
scanf("%d", &a[i]);Bütün çubuq altçoxluqlarını seçək və onların ümumi uzunluğunu hesablayın.
for (i = 0; i < 1 << n; i++)
for (j = 0; j < n; j++)
if (i & (1 << j)) sum[i] += a[j];Sonra bütün mümkün çubuq altçoxluqlarını seçək. Əgər bir çoxluq üçün bir altçoxluq J \subset I varsa ki, -dəki çubuqların ümumi uzunluğu -dəki çubuqların ümumi uzunluğunun yarısına bərabərdirsə, onda can[I] = true təyin edərək bu çubuqları düzbucaqlının qarşı-qarşıya duran tərəfləri kimi istifadə edə bilərik.
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;
}
}Bütün çubuqların altçoxluqlarını seçirik. Əgər bir çoxluq üçün bir altçoxluq J \subset I varsa ki, can[J] = true və can[I~xor~J] = true, onda bu, çubuqların üfüqi və şaquli tərəflər arasında bir mümkün düzülüşüdür. Belə bir düzbucaqlının tərəflərinin uzunluqları sum[J] / 2 və sum[I xor J] / 2 olur.
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);Ən böyük ölçüsü olan tapılmış düzbucaqlının sahəsini çıxarırıq.
printf("%lld\n", res);