/*
translation:
给出一个n行m列的草地,1表示肥沃,0表示贫瘠,现在要把一些牛放在肥沃的草地上,但是要求所有牛不能相邻,问你有多少种放法
solution:
状态压缩dp
每次枚举时候判断是否符合当前草地的情况,再判断是否跟前面的一行兼容。
note:
* 将所有合法状态预先处理存进一个数组里面即可提高速度
# 一开始check(i, s)WA了好多次,后来发现应该是check(i, st[s])。
date:
2017.1.1-----跨年快乐。
*/
#include <iostream>
#include <cstdio>
#include <cstring>
typedef long long ll;
using namespace std;
const int maxn = 15;
const int mod = 100000000;
int dp[maxn][1 << maxn], m, n, G[maxn][maxn];
int st[1 << maxn]; //存放预处理求出的符合要求的状态
void init()
{
int id = 0;
memset(st, 0, sizeof(st));
for(int i = 0; i < 1 << maxn; i++) if(!(i & (i << 1))){
st[id++] = i; //将所有不相邻的状态存放进st数组当中
}
}
bool check(int row, int s) //检查在第row行的s状态是否非法
{
for(int i = 0; i < n; i++){
if((s >> i & 1) && !G[row][i])
return false;
}
return true;
}
int main()
{
//freopen("in.txt", "r", stdin);
init();
while(~scanf("%d%d", &m, &n)){ //m--行 n--列
memset(G, 0, sizeof(G));
memset(dp, 0, sizeof(dp));
for(int i = 0; i < m; i++){
for(int j = 0; j < n; j++){
scanf("%d", &G[i][j]);
}
}
//dp[i][s]表示到目前第i行的s状态为止,总共有多少种方案
for(int i = 0; st[i] < 1 << n; i++)
if(check(0, st[i]))dp[0][i] = 1;
for(int i = 1; i < m; i++){
for(int pres = 0; st[pres] < 1 << n; pres++){ //枚举前一行的状态
for(int s = 0; st[s] < 1 << n; s++) if(!(st[s] & st[pres]) && check(i, st[s])){ //枚举当前行的状态
dp[i][s] += dp[i-1][pres];
}
}
}
ll res = 0;
for(int s = 0; st[s] < 1 << n; s++){
res += dp[m-1][s];
}
printf("%d\n", res % mod);
}
return 0;
}
poj3254(常见的二维状压dp)
最新推荐文章于 2020-11-12 23:14:27 发布