1. 程式人生 > 實用技巧 >[USACO06NOV]Corn Fields G

[USACO06NOV]Corn Fields G

洛谷AC通道!

一看題目,肯定就是狀態壓縮的題目。

設$f_{i,k}$表示: 在第$i$行的時候,二進位制狀態$k$下的方案數量。

首先,我們要保證一個狀態下在自己那一行是合法的,那麼用$g_i$記錄狀態$i$是否合法。

繼續,我們還要保證上下兩行不能有相鄰的邊,即$(j$ & $k) == 0$, 保證所有的$1,0$全部錯開。

如果都合法,那我們直接把狀態累計的數量加起來就ok啦!

#include <bits/stdc++.h>
using namespace std;
#define N ((1<<12)+10)
const int mod = (int
)1e8; template <class T> inline void read(T& a){ T x = 0, s = 1; char c = getchar(); while(!isdigit(c)){ if(c == '-') s = -1; c = getchar(); } while(isdigit(c)){ x = x * 10 + (c ^ '0'); c = getchar(); } a = x * s; return ; } int
F[N]; // 記錄每一行的所有狀態 int g[N]; // 記錄這種狀態是否合法 int dp[13][N], a[N][N]; int n, m; int main(){ read(m), read(n); for(int i = 1; i <= m; i++) for(int j = 1; j <= n; j++){ read(a[i][j]); F[i] = (F[i] << 1) + a[i][j]; // 儲存每一行的狀態 } for(int i = 0
; i < (1 << n); i++) g[i] = (!(i & (i << 1))) && (!(i & (i >> 1))); // g[i] 保證 i 這一狀態合法(所有行通用) dp[0][0] = 1; for(int i = 1; i <= m; i++){ for(int j = 0; j < (1 << n); j++){ if(g[j] && ((j & F[i]) == j)){ // 保證在肥沃的草地上 for(int k = 0; k < (1 << n); k++){ if((k & j) == 0) // 保證上一行和這一行沒有公共邊 dp[i][j] = (dp[i][j] + dp[i-1][k]) % mod; // 累加 } } } } int ans = 0; for(int i = 0; i < (1 << n); i++) ans = (ans + dp[m][i]) % mod; // 最後一行所有的狀態的總和 cout << ans << endl; return 0; }