Çubuqlar#1405

Çubuqlar (Həll təhlili)

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);