Меры предосторожности:
Предупредите о сложности дп!
Это название является приблизительным названием "State Compression dp—Мечта Мондриана" . Рекомендуется сначала прочитать эту статью и понять ее.
Название:
Расположите k королей на шахматной доске n × n, короли могут атаковать 8 соседних клеток, и найдите общее количество схем, которые не позволяют им атаковать друг друга.
Формат ввода
Всего одна строка, содержащая два целых числа n и k.
Формат вывода
Всего одна строка, указывающая общее количество решений, если ее нельзя разместить, выведите 0.
Диапазон данных
1≤n≤10,
0≤k≤n^2
输入:
3 2
输出:
16
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int N = 12, M = 1 << 10, K = 110;
int n, m; //棋盘大小n*n, 有m个国王,
long long f[N][K][M]; //f[i][j][k],对于前i层的棋盘,总共放了j个国王,且第i层的状态为k(比如k是0101,1表示放了国王,0表示没放)的方案,
int c[M]; //count[i]为第i层国王的数量,
vector<int> state; //state存储所有合法状态,
vector<int> state_trans[M]; //state_trans[a] = {b1, b2, b3}存储能从合法状态a转移到的合法状态b,
bool check(int s) {
//检查当前状态(二进制)是否存在连续的两个1,存在返回false不合法,不存在返回true合法。
for (int i = 0; i<n; i++) {
if ((s >> i & 1) && (s >> (i+1) & 1)) return false;
}
return true;
}
int count(int s) {
//统计当前状态(二进制)中存在多少个1,也就是找到当前行中国王的个数。
int res = 0;
for (int i = 0; i<n; i++) res += (s >> i & 1);
return res;
}
int main() {
cin >> n >> m;
//预处理所有合法方案
for (int i = 0; i < (1<<n); i++) {
if (check(i)) {
//如果当前状态合法,存入state,并计算状态中国王的数量。
state.push_back(i);
c[i] = count(i);
}
}
//预处理所有合法状态可以转移到的合法状态, 满足两种情况即可转移:
//1.状态a和状态b的&,为0,代表不存在交集, (比如01001和01010,&后就是01000,还有1存在说明肯定有两个国王会相互攻击到)
//2.状态a和状态b的|,不能存在两个连续的1,也就是需要转移后的方案是合法方案,
for (auto &a : state){
for (auto &b : state) {
if ((a&b)==0 && check(a|b)) {
state_trans[a].push_back(b); //符合两个条件,就说明能够从a转移到的状态b
}
}
}
//dp
f[0][0][0] = 1; //初始化,对于前0行,总共摆放了0个国王,且第0行的状态为0(一个都没摆),是一种合法方案。
for (int i = 1; i<=n+1; i++) {
//枚举棋盘的每一行(枚举到n+1行是一个小优化)
for (int j = 0; j<=m; j++) {
//枚举国王数量
for (auto &a : state) {
//枚举合法状态a
for (auto &b : state_trans[a]) {
//枚举所有能够从a转移到的状态b
if (j - c[a] >= 0) {
//如果当前剩余的国王足够摆放,就可以进行状态更新
f[i][j][a] += f[i-1][j-c[a]][b];
}
}
}
}
}
//这里就将枚举到n+1行的优化体现出来了,f[n+1][m][0]代表,对于前n+1行,总共摆放了m个国王,且第i+1行的状态为0(一个都没摆),
//那其实也就代表了前i行摆了m个国王的总方案数。
cout << f[n+1][m][0];
return 0;
}
Идея:
Грядет захватывающий дп (плачет), или классический метод дп в стиле y
1. Представление состояния
f[i][j][k]
:
Для предыдущей строки шахматной доски (включая i-ю строку) i
поставлен j
король , а i
состояние линии - k
количество шашек,
атрибут - Счет,
(Состояние k здесь относится к двоичному представлению «положения короля» в строке, например, 0101, что означает, что король находится на 2-й и 4-й сетках, что равно 5 в десятичной системе, что обычно используется в методе сжатия состояния dp для хранения состояния)
2. Расчет состояния
1. Прежде всего, давайте подумаем, какое состояние (одна строка) допустимо?
То есть для одного и того же ряда разрешено сохранять по крайней мере одно расстояние сетки между королем и королем.
(Картинка взята из заимствованного цветного ведущего босса , зеленый — король, а красный — дальность атаки):
Во-вторых, давайте подумаем, при каких обстоятельствах возможно обновление статуса (две строки)?
То есть, когда оба состояния a и b являются допустимыми,
1. Операция AND a и b равна 0 (то есть a и b не могут иметь королей в одной и той же позиции)
2. Операция OR a и b Результат не существует последовательных королей (то есть результат является допустимым состоянием)
После выполнения вышеуказанных условий можно, наконец, выполнить передачу состояния:
f[i][j][a] += f[i-1][j-c[a]][b]
Непосредственно объясните из практического смысла:
- строка i, общее количество королей, размещенных на доске, равно j, а состояние строки i равно a, вы
можете начать с
- строки i-1, общее количество королей, размещенных на доске доска "Общее количество королей - количество королей в состоянии a", а состояние строки i - это b, и
выполняется перенос суперпозиции.
Если это полезно, пожалуйста, дайте бесплатный лайк ~ Кто-то, кто смотрит, - это мотивация, чтобы поддержать меня, чтобы записать!
Отказ от ответственности:
источником идеи алгоритма является г-н Y. Для получения подробной информации см. https://www.acwing.com/
Эта статья используется только для изучения записей и обменов