/*
状态压缩dp
每一行的可行状态进行压缩 , n=3时 s = {000, 001, 010, 100, 101}
d[row][si][p] 表示 第row行状态为si,前row-1行已放置且不冲突,总共放了p个棋子的方案数
初始状态 d[0][0][0] = 1, others = 0;
递推公式 d[row][s[i]][p + c[i]] = sigma(d[row-1][s[j]][p])
最终解 sigma(d[n][i][k])
小优化: 将上下两行相容的状态存储起来,不用在每次dp时重复判断
*/
#include <stdio.h>
#define SIZE 146
int n, k;
int sc = 0; //状态总数
int s[SIZE], c[SIZE]; //每行的可能状态s,每个状态的棋子(1)个数
long long d[12][SIZE][200];
int r[2][690]; //上下两行可相容的状态,特许情况(0,0)
int rs = 0; //相容状态总数
// n*n棋盘最多放置棋子数, 写出程序后 根据结果手动添加的
int bounds[] = {0, 2, 2, 5, 5, 10, 10, 17, 17, 26, 26 };
//判断状态是否相容
int check(int si, int sj) {
if ((si&sj) != 0) return 0;
if (((si<<1)&sj) != 0) return 0;
if (((sj<<1)&si) != 0) return 0;
if (((si>>1)&sj) != 0) return 0;
if (((sj>>1)&si) != 0) return 0;
return 1;
}
//搜索出所有可行状态
void dfs(int si, int ci, int len) {
if (len == n) {
s[sc] = si;
c[sc] = ci;
++sc;
}
else{
dfs(si<<1, ci, len+1);
if ((si&1) == 0) {
dfs((si<<1) | 1, ci + 1, len + 1);
}
}
}
int main() {
scanf("%d%d", &n, &k);
if (k >= bounds[n]) {
printf("0\n");
return 0;
}
if (k == 0) {
printf("1\n");
return 0;
}
dfs(0, 0, 0);
d[0][0][0] = 1;
// 初始化相容状态
int i, j;
for ( i=0; i<sc; ++i) {
for ( j=i; j<sc; ++j) {
if (check(s[i], s[j])) {
r[0][rs] = i;
r[1][rs] = j;
++rs;
}
}
}
//dp求解
int row = 1;
while (row <= n) {
for (i=0; i<rs; ++i) {
for (j=0; j<=k; ++j) {
int r1 = r[0][i];
int r2 = r[1][i];
d[row][r1][j+c[r1]] += d[row-1][r2][j];
if (r1 != r2) {
d[row][r2][j+c[r2]] += d[row-1][r1][j];
}
}
}
++row;
}
long long ans = 0;
for (i=0; i<sc; ++i) {
ans += d[n][i][k];
}
printf("%lld\n", ans);
return 0;
}
sgu 223
最新推荐文章于 2024-04-07 22:08:13 发布