Розрізання прямокутника#11722

Розрізання прямокутника (Розбір)

Нехай f(a, b) — найменша кількість ходів, за яке прямокутник розміром a \times b можна розрізати на квадрати. Будемо зберігати це значення в осередку .

Якщо прямокутник вже є квадратом (a = b), розрізи не потрібні, тому f(a, a) = 0.

Прямокутник a \times b можна розрізати або вертикальним, або горизонтальним розрізом. Розглянемо спочатку вертикальний розріз.

При вертикальному розрізі прямокутник a \times b ділиться на два прямокутники: a \times k і a \times (b - k). Щоб отримані прямокутники були невиродженими, повинна виконуватися умова 1 \le k < b. Потім рекурсивно розв'язуємо задачу для кожного з цих двох прямокутників і додаємо до результату, оскільки ми зробили один вертикальний розріз. При цьому обираємо таке , для якого сума f(a, k) + f(a, b - k) + 1 найменша:

f(a, b) = \min_{\substack{1 \le k < b}} (f(a, k) + f(a, b - k)) + 1

Для випадку горизонтального розрізу отримуємо аналогічну формулу:

f(a, b) = \min_{\substack{1 \le k < a}} (f(k, b) + f(a - k, b) + 1

Залишається вибрати мінімальне значення серед цих двох варіантів.

Приклад

У першому тесті потрібно виконати розрізи:

Реалізація алгоритму

Оголосимо константи і робочий масив.

#define MAX 501
#define INF 0x3F3F3F3F

int dp[MAX][MAX];

Функція f(a, b) повертає найменшу кількість ходів, за яке прямокутник розміром a \times b можна розрізати на квадрати.

int f(int a, int b)
{

Якщо прямокутник вже є квадратом (a = b), розрізи не потрібні.

  if (a == b) return 0;

Якщо значення f(a, b) ще не обчислено (dp[a][b] = ∞), то обчислюємо його.

  if (dp[a][b] == INF)
  {

Виконуємо всі можливі вертикальні розрізи.

    for (int k = 1; k < b; k++)
      dp[a][b] = min(dp[a][b], f(a, k) + f(a, b - k) + 1);

Виконуємо всі можливі горизонтальні розрізи.

    for (int k = 1; k < a; k++)
      dp[a][b] = min(dp[a][b], f(k, b) + f(a - k, b) + 1);
  }

Повертаємо результат f(a, b) = dp[a][b].

  return dp[a][b];
}

Основна частина програми. Читаємо розміри прямокутника і .

scanf("%d %d", &a, &b);

Обчислюємо і виводимо відповідь.

memset(dp, 0x3F, sizeof(dp));
printf("%d\n", f(a, b));