题意
一个 的方格,有的地方能放人,有的不能。人不能上下左右相邻放置。问放置方案总数。
题解
看到 这么小就知道是状压 DP。
以表示行的状态为例,设 为前
行处理完并且第
行的状态为
时的方案数目。那么只需要以行编号为阶段,内部枚举本行状态和上一行状态进行转移即可。
时间复杂度为 。
(注意非法状态的处理。)
#include <bits/stdc++.h> #define INF 2000000000 #define MOD 100000000 #define MAXN 200005 #define REP(temp, init_val, end_val) for (int temp = init_val; temp <= end_val; ++temp) #define REPR(temp, init_val, end_val) for (int temp = init_val; temp >= end_val; --temp) using namespace std; typedef long long ll; typedef unsigned long long ull; typedef pair<int, int> intpair; int read(){ int f = 1, x = 0; char c = getchar(); while (c < '0' || c > '9'){if(c == '-') f = -f; c = getchar();} while (c >= '0' && c <= '9')x = x * 10 + c - '0', c = getchar(); return f * x; } inline int lowbit(int x){ return x & (-x); } inline int modadd(int x, int y){ return (x + y >= MOD ? x + y - MOD: x + y); } inline int sgn(int x){ return (x < 0 ? -1: (x > 0 ? 1: 0)); } template<typename T> T gcd(T a, T b){ return (!b) ? a: gcd(b, a % b); } const int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1}; /*--------------------------------------------------------------------*/ /*--------------------------------------------------------------------*/ int n, m, a[15][15], b[15] = {0}; int f[15][(1 << 13)]; void init(){ memset(b, 0, sizeof(b)); REP(i, 1, n){ REP(j, 1, m){ a[i][j] = read(); if (!a[i][j]) b[i] |= (1 << j >> 1); } } memset(f, -1, sizeof(f)); f[0][0] = 1; } void solve(){ REP(i, 1, n){ REP(j, 0, (1 << m) - 1){ if (j & b[i]) continue; if (j & (j << 1)) continue; if (j & (j >> 1)) continue; REP(k, 0, (1 << m) - 1){ if (f[i - 1][k] < 0) continue; if (k & j) continue; if (f[i][j] < 0) f[i][j] = 0; f[i][j] = modadd(f[i][j], f[i - 1][k]); // cout << i << " " << j << " " << f[i][j] << endl; } } } int ans = 0; REP(j, 0, (1 << m) - 1){ if (f[n][j] >= 0) ans = modadd(ans, f[n][j]); } printf("%d\n", ans); } int main(){ while (scanf("%d%d", &n, &m) == 2){ init(); solve(); } return 0; }