首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

POJ 3254 Corn Fields:狀壓 DP + 滾動數組計數放牛方案

     編輯:關於C++

問題描述

N 行 M 列草地(N≤12, M≤12),部分格子不能放牛(輸入 0)。每行牛不能相鄰,相鄰行牛也不能垂直相鄰。求合法放置方案數模 10⁸。

狀壓 DP 設計

  • 狀態:每行用 M 位二進制數表示放牛情況(1 放,0 不放)。
  • 合法狀態條件:
      1. 無相鄰 1:(s & (s<<1)) == 0。
      2. 不佔用禁區:(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< 節省空間。

代碼實現 (C++)

#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;
}

複雜度

  • 狀態數 ≤ 2¹² = 4096,實際合法狀態約 300~500。
  • 轉移:O(N × |valid|²) ≈ 12 × 500² = 3e6,極快。
  • 空間:O(2^M)。

關鍵點

  • 位運算判斷合法:(s & (s<<1)) == 0 檢查水平相鄰,(s & t) == 0 檢查垂直相鄰。
  • 滾動數組將空間從 O(N·2^M) 降至 O(2^M)。
  • 模 10⁸ 非質數,僅做加法取模。

這題是狀壓 DP 入門經典題,展示了「逐行狀態 + 相容性轉移」的標準框架,滾動數組優化空間是必備技巧。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved