E134. Расстановка слонов на шахматной доске
Источник: e-maxx.ru/algo, страница PDF 430.
Требуется найти количество способов расставить K слонов на доске размером NxN.
Алгоритм
Решать задачу будем с помощью динамического программирования. Пусть D[i][j] - количество способов расставить j слонов на диагоналях до i-ой включительно, причём только тех диагоналях, которые того же цвета, что и i-ая диагональ. Тогда i = 1..2N-1, j = 0..K. Диагонали занумеруем следующим образом (пример для доски 5x5): черные: белые:
1 _ 5 _ 9 _ 2 _ 6 _
_ 5 _ 9 _ 2 _ 6 _ 8
5 _ 9 _ 7 _ 6 _ 8 _
_ 9 _ 7 _ 6 _ 8 _ 4
9 _ 7 _ 3 _ 8 _ 4 _
Т.е. нечётные номера соответствуют чёрным диагоналям, чётные - белым; диагонали нумеруем в порядке увеличения количества элементов в них. При такой нумерации мы можем вычислить каждое D[i][], основываясь только на D[i-2][] (двойка вычитается, чтобы мы рассматривали диагональ того же цвета). Итак, пусть текущий элемент динамики - D[i][j]. Имеем два перехода. Первый - D[i-2][j], т.е. ставим всех j слонов на предыдущие диагонали. Второй переход - если мы ставим одного слона на текущую диагональ, а остальных j-1 слонов - на предыдущие; заметим, что количество способов поставить слона на текущую диагональ равно количеству клеток в ней минус j-1, т.к. слоны, стоящие на предыдущих диагоналях, будут перекрывать часть направлений. Таким образом, имеем:
D[i][j] = D[i-2][j] + D[i-2][j-1] (cells(i) - j + 1)
где cells(i) - количество клеток, лежащих на i-ой диагонали. Например, cells можно вычислять так:
int cells (int i) {
if (i & 1)
return i / 4 * 2 + 1;
else
return (i - 1) / 4 * 2 + 2;
} Осталось определить базу динамики, тут никаких сложностей нет: D[i][0] = 1, D[1][1] = 1. Наконец, вычислив динамику, найти собственно ответ к задаче несложно. Перебираем количество i=0..K слонов, стоящих на чёрных диагоналях (номер последней чёрной диагонали - 2N-1), соответственно K-i слонов ставим на белые диагонали (номер последней белой диагонали - 2N-2), т.е. к ответу прибавляем величину D[2N-1][i] * D[2N-2][K-i].
Реализация
int n, k; // входные данные
if (k > 2*n-1) {
cout << 0;
return 0;
}
vector < vector<int> > d (n*2, vector<int> (k+2));
for (int i=0; i<n*2; ++i)
d[i][0] = 1;
d[1][1] = 1;
for (int i=2; i<n*2; ++i)
for (int j=1; j<=k; ++j)
d[i][j] = d[i-2][j] + d[i-2][j-1] * (cells(i) - j + 1);
int ans = 0;
for (int i=0; i<=k; ++i)
ans += d[n*2-1][i] * d[n*2-2][k-i];
cout << ans;
C# решение
auto-draft, проверить перед отправкойusing System;
using System.Collections.Generic;
using System.Linq;
public static class AlgorithmDraft
{
// Auto-generated C# draft from the original e-maxx C/C++ listing. Review before production use.
черные: белые:
1 _ 5 _ 9 _ 2 _ 6 _
_ 5 _ 9 _ 2 _ 6 _ 8
5 _ 9 _ 7 _ 6 _ 8 _
_ 9 _ 7 _ 6 _ 8 _ 4
9 _ 7 _ 3 _ 8 _ 4 _
D[i][j] = D[i-2][j] + D[i-2][j-1] (cells(i) - j + 1)
int cells (int i) {
if (i & 1)
return i / 4 * 2 + 1;
else
return (i - 1) / 4 * 2 + 2;
}
int n, k; // входные данные
if (k > 2*n-1) {
Console.WriteLine( 0;
return 0;
}
vector < List<int> > d (n*2, List<int> (k+2));
for (int i=0; i<n*2; ++i)
d[i][0] = 1;
d[1][1] = 1;
for (int i=2; i<n*2; ++i)
for (int j=1; j<=k; ++j)
d[i][j] = d[i-2][j] + d[i-2][j-1] * (cells(i) - j + 1);
int ans = 0;
for (int i=0; i<=k; ++i)
ans += d[n*2-1][i] * d[n*2-2][k-i];
Console.WriteLine( ans;
}
C++ решение
сопоставлено/оригиналчерные: белые:
1 _ 5 _ 9 _ 2 _ 6 _
_ 5 _ 9 _ 2 _ 6 _ 8
5 _ 9 _ 7 _ 6 _ 8 _
_ 9 _ 7 _ 6 _ 8 _ 4
9 _ 7 _ 3 _ 8 _ 4 _
D[i][j] = D[i-2][j] + D[i-2][j-1] (cells(i) - j + 1)
int cells (int i) {
if (i & 1)
return i / 4 * 2 + 1;
else
return (i - 1) / 4 * 2 + 2;
}
int n, k; // входные данные
if (k > 2*n-1) {
cout << 0;
return 0;
}
vector < vector<int> > d (n*2, vector<int> (k+2));
for (int i=0; i<n*2; ++i)
d[i][0] = 1;
d[1][1] = 1;
for (int i=2; i<n*2; ++i)
for (int j=1; j<=k; ++j)
d[i][j] = d[i-2][j] + d[i-2][j-1] * (cells(i) - j + 1);
int ans = 0;
for (int i=0; i<=k; ++i)
ans += d[n*2-1][i] * d[n*2-2][k-i];
cout << ans;
Java решение
auto-draft, проверить перед отправкойimport java.util.*;
import java.math.*;
public class AlgorithmDraft {
// Auto-generated Java draft from the original e-maxx C/C++ listing. Review before production use.
черные: белые:
1 _ 5 _ 9 _ 2 _ 6 _
_ 5 _ 9 _ 2 _ 6 _ 8
5 _ 9 _ 7 _ 6 _ 8 _
_ 9 _ 7 _ 6 _ 8 _ 4
9 _ 7 _ 3 _ 8 _ 4 _
D[i][j] = D[i-2][j] + D[i-2][j-1] (cells(i) - j + 1)
int cells (int i) {
if (i & 1)
return i / 4 * 2 + 1;
else
return (i - 1) / 4 * 2 + 2;
}
int n, k; // входные данные
if (k > 2*n-1) {
System.out.println( 0;
return 0;
}
vector < ArrayList<Integer> > d (n*2, ArrayList<Integer> (k+2));
for (int i=0; i<n*2; ++i)
d[i][0] = 1;
d[1][1] = 1;
for (int i=2; i<n*2; ++i)
for (int j=1; j<=k; ++j)
d[i][j] = d[i-2][j] + d[i-2][j-1] * (cells(i) - j + 1);
int ans = 0;
for (int i=0; i<=k; ++i)
ans += d[n*2-1][i] * d[n*2-2][k-i];
System.out.println( ans;
}
Материал разбит как алгоритмическая задача: изучить постановку, понять асимптотику и реализовать алгоритм на выбранном языке.
Вакансии для этой задачи
Показаны активные вакансии с пересечением по тегам задачи.