POJ 3254 Corn Fields 状态压缩DP

题意:John买了一块矩形的地。他想在上面种草喂奶牛,但是有的格子比较贫瘠不能种草,我们用0表示。否则用1表示。由于奶牛不喜欢挤在一起,所以任何两个相邻格子不能都种上草。现在问你有多少种种草的方式。当然,不种草也算一种方式。
题解:第 i 行的第 j 中状态由前一行决定。故枚举第 i - 1 行中所有与 j 相容的状态。

#include <iostream>
using namespace std;

#define Num 100000000
#define N (1<<13)
bool state[13][N]; /* state[i][j] 表示第i行可以化成状态j,每一行的其他状态都是由其初始状态转移的到得 */
int dp[13][N], row[13]; /* row[i]表示第i行的初始状态 */
int Max, R, C;

void calState ( int i )
{
	for ( int k = 0; k <= Max; k++ )
	{   
		if ( ((~row[i]) & k) || (k & (k<<1)) )  /* 一开始用的是(row[i]&(~k)),没注意到位运算会修改掉原来的值,WR了很久 */ 
			state[i][k] = 0;
		else state[i][k] = 1;
	}
}

void operDp ()
{
	int i, j, k;
	for ( i = 0; i <= Max; i++ ) /* 预先把第一行的值求出来 */
	{
		if ( state[1][i] )
			dp[1][i] = 1;
	}

	for ( i = 2; i <= R; i++ )
	{
		for ( j = 0; j <= Max; j++ )
		{
			if ( ! state[i][j] ) /* 若第i行的状态j不存在,直接用第i行下一个状态 */
				continue;
		    for ( k = 0; k <= Max; k++ )
			    if ( state[i-1][k] && !(j & k) ) /* 若第i-1行的状态k存在,且状态k与状态j直接不冲突,则dp[i][j]累加 */
					dp[i][j] += dp[i-1][k];
			dp[i][j] %= Num;
		}
	}
}

int main()
{
	scanf("%d%d",&R,&C);
	Max = 1 << C;
	memset(state,0,sizeof(state));
	memset(dp,0,sizeof(dp));

	int i, j, flag;
	for ( i = 1; i <= R; i++ )
	{
		for ( j = 0; j < C; j++ )
		{
		    scanf("%d",&flag);
		    row[i] |= ( flag << j );
		}
		calState ( i );
	}

	operDp();
	int ans = 0;
	for ( i = 0; i <= Max; i++ )
		ans += dp[R][i];
	printf("%d\n",ans % Num);
	return 0;
}


你可能感兴趣的:(c)