N 行 M 列草地(N≤12, M≤12),部分格子不能放牛(輸入 0)。每行牛不能相鄰,相鄰行牛也不能垂直相鄰。求合法放置方案數模 10⁸。
(s & (s<<1)) == 0。(s & ~land[row]) == 0(land[row] 為該行可放位掩碼)。vector valid[row] 。dp[row][s] = sum_{t in valid[row-1], (s & t) == 0} dp[row-1][t]
即:當前行狀態 s 與上一行狀態 t 無垂直衝突(按位與為 0)。
用滾動數組 dp[2][1<
#include <bits/stdc++.h>
using namespace std;
const int MOD = 100000000;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m; cin >> n >> m;
vector land(n);
for (int i = 0; i < n; ++i) {
int mask = 0;
for (int j = 0; j < m; ++j) {
int x; cin >> x;
if (x) mask |= 1 << j;
}
land[i] = mask;
}
vector> valid(n);
int ALL = 1 << m;
for (int i = 0; i < n; ++i) {
for (int s = 0; s < ALL; ++s) {
if ((s & (s<<1)) == 0 && (s & ~land[i]) == 0)
valid[i].push_back(s);
}
}
vector dp(ALL), ndp(ALL);
for (int s : valid[0]) dp[s] = 1;
for (int i = 1; i < n; ++i) {
fill(ndp.begin(), ndp.end(), 0);
for (int s : valid[i]) {
for (int t : valid[i-1]) {
if ((s & t) == 0) {
ndp[s] += dp[t];
if (ndp[s] >= MOD) ndp[s] -= MOD;
}
}
}
dp.swap(ndp);
}
int ans = 0;
for (int s : valid[n-1]) {
ans += dp[s];
if (ans >= MOD) ans -= MOD;
}
cout << ans << '\n';
return 0;
}
(s & (s<<1)) == 0 檢查水平相鄰,(s & t) == 0 檢查垂直相鄰。這題是狀壓 DP 入門經典題,展示了「逐行狀態 + 相容性轉移」的標準框架,滾動數組優化空間是必備技巧。