poj3254 Corn Fields 状压DP入门

题目大意:n*m的矩阵01中1处可以种植 0处不能种植,有多少种放法,并且任意两个不能相邻

解题思路 : 对于本题用二进制表示,设f[i][st]为当前行的状态,当前行的合法状态只和上一行有关

状态转移方程:f[i][st] += f[i-1][]st'],其中st和st‘没有冲突且st没有连续的1

下边就是一些位运算操作算是积累了 

st&(st>>1)为真表示有相邻的1,x&y为真表示有相邻行有冲突。


#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
const int maxn = (1<<12) + 5;
const int INF = 0x7f7f7f7f;
const int mode = 100000000;

int a[maxn], b[maxn];
long long f[13][maxn];//长见识了f[12][maxn]时c++会RE,G++就过了
int maze[15][15];
int n, m;
inline bool can(int st, int r)
{
	int i = n, t = st;
	if (st & (st >> 1)) return false;
	while(t) {
		if (t%2 == 1 && !maze[r][i]) return false;
		i--;
		t >>= 1;
	}
	return true;
}

inline bool check(int x, int y)
{
	return !(x & y);
}
int main()
{
    //freopen("input.txt", "r", stdin);
    while (cin >> m >> n)
    {
    	memset(f, 0, sizeof(f));
        for (int i = 1; i <= m; i++)
			for (int j = 1; j<= n; j++)
			scanf("%d", &maze[i][j]);
		int cnt = 0;
		for (int st = 0; st < (1<<n); st++)//边界
		{
			if (can(st, 1)) {
				f[1][st] = 1;
				a[cnt++] = st;
			}
		}
		for (int i = 2; i <= m; i++)
		{
			int tot = 0;
			for (int st = 0; st < (1<<n); st++)
			{
				int flag = 0;
				if (can(st, i))
					for (int j = 0; j < cnt; j++)
						if (check(st, a[j]))
						{
							flag = 1;
							f[i][st] += f[i-1][a[j]];
						}
				if (flag) b[tot++] = st;
			}
			cnt = tot;
			memcpy(a, b, sizeof(b));
		}
		long long ans = 0;
		for (int i = 0; i < (1<<n); i++) ans += f[m][i];
		cout << ans%mode << endl;

    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值