您的位置:首页 > 其它

poj3254(常见的二维状压dp)

2017-01-01 01:19 162 查看
/*
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: