Corn Fields(poj 3254)
M和N的范围为1-12,每一列都含有2N种可能性(需要进一步缩小),对于其中的一种可能性,可以由前一列是否和该列有关来进行匹配,最后进行叠加所有匹配的情况即可。
时间复杂度为O(M*2N*2N)
假设前一列的状态为x,当前列的状态为y,那么y可以接着种在x后面的判断表达式为x&y=0
同时,在每一列上,上下两个也不能相邻,因此首先需要预处理出所有可能的取值情况为j&(j<1)=0
然后具体的列上,j是否是可能的取值的判断表达式为j &s=j
最后输出总的和即可。
#include<iostream>
#include<vector>
using namespace std;
#define NMAX 13
vector<int > P;
int S[NMAX];
int M, N;
int dp[NMAX][1 << NMAX];
int main() {
while (scanf_s("%d%d", &M, &N) == 2) {
P.clear();
for (int i = 0; i < (1 << N); i++) {
if ((i & (i << 1)) == 0 && (i & (i >> 1)) == 0) P.push_back(i);
}
for (int i = 0; i < M; i++) {
int sum = 0, cur;
for (int j = 0; j < N; j++) {
scanf_s("%d", &cur);
sum = 2 * sum + cur;
}
S[i] = sum;
}
//初始化第一行
memset(dp, 0, sizeof(dp));
for (int i = 0; i < P.size(); i++) {
if ((P[i] & S[0]) == P[i]) dp[0][P[i]] = 1;
}
for (int i = 1; i < M; i++) {
for (int j = 0; j < P.size(); j++) {
if ((P[j] & S[i]) == P[j]) {
for (int k = 0; k < P.size(); k++) {
if ((P[k] & S[i - 1]) == P[k]) {
if ((P[j] & P[k]) == 0) dp[i][P[j]] += dp[i - 1][P[k]];
}
}
}
}
}
long long sum = 0;
for (int i = 0; i < P.size(); i++) sum += dp[M - 1][P[i]];
printf("%d\n", sum % 100000000);
}
}
tip:
1.最终的结果需要模上1e8,否则会WA