POJ3254-Corn Fields(状态压缩)

Farmer John has purchased a lush new rectangular pasture composed of M by N (1 ≤ M ≤ 12; 1 ≤ N ≤ 12) square parcels. He wants to grow some yummy corn for the cows on a number of squares. Regrettably, some of the squares are infertile and can’t be planted. Canny FJ knows that the cows dislike eating close to each other, so when choosing which squares to plant, he avoids choosing squares that are adjacent; no two chosen squares share an edge. He has not yet made the final choice as to which squares to plant.

Being a very open-minded man, Farmer John wants to consider all possible options for how to choose the squares for planting. He is so open-minded that he considers choosing no squares as a valid option! Please help Farmer John determine the number of ways he can choose the squares to plant.

Input
Line 1: Two space-separated integers: M and N
Lines 2…M+1: Line i+1 describes row i of the pasture with N space-separated integers indicating whether a square is fertile (1 for fertile, 0 for infertile)
Output
Line 1: One integer: the number of ways that FJ can choose the squares modulo 100,000,000.
Sample Input
2 3
1 1 1
0 1 0
Sample Output
9
Hint
Number the squares as follows:
1 2 3
4

There are four ways to plant only on one squares (1, 2, 3, or 4), three ways to plant on two squares (13, 14, or 34), 1 way to plant on three squares (134), and one way to plant on no squares. 4+3+1+1=9.

分析:

题意:
在一块n行m列的土地上种草,如果(x,y)的值为1,则这块地肥沃,可以种草;如果值为0,那么这块土地就比较贫瘠,无法种植,现在农场主要在这些土地上种草并放养奶牛,不放养的肥沃的土地可以不种,但是这些奶牛有一个要求,就是这些奶牛不能成为邻居,即放牧的地没有公共边,问在这样的土地上有多少种不同的种植方法?

解析:
这不是我的第一道状态压缩的题了,但是开始看这道提还是一筹莫展,太菜了!

我们将每块地种和不种分别用1和0表示,那么我们以一行3块土地来看,那么它的种植方法有:

种植的方法二进制十进制
全不种0000
只种第一块1004
只种第二块0102
只种第三块0011
种第一、二块1106
种第二、三块0113
种第一、三块1015
全种1117

那么他们对应的值各不相同,且恰为23种,每个数对应一种方法,这就是状态压缩!

我们在根据题目的要求对一些情况进行选择!

代码:

#include<iostream>
#include<cstdio>
#define N 15
#define Mod 100000000

using namespace std;

int n,m;
int map[N][N];
int dp[N][1<<12+10];

bool cmp(int a,int b)
{
	if(b&(b<<1)) //如果有两个1紧挨着,那么在同一行上面是不符合条件的,就不用继续检测同列了
		return false;
	for(int i=1;i<=m;i++)//判断是否在不肥沃的土地上种上了草 
	{
		if(!map[a][i]) //若这处是不能种植的
		{
			if(((1<<(m-i))&b)!=0) //但是这种状态下此处种了树	
			return false;
		}
	}
	return true;
}

int main()
{
	while(~scanf("%d%d",&n,&m))
	{
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=m;j++)
			{
				scanf("%d",&map[i][j]);
			}
		}
		dp[0][0]=1;
		long long sum=0;
		for(int i=1;i<=n;i++)
		{
			for(int j=0;j<(1<<m);j++)
			{
				if(cmp(i,j))
				{
					for(int k=0;k<(1<<m);k++)
					{
						if(!(k&j))
							dp[i][j]+=dp[i-1][k]; 
					}
				}
			}
		}
		for(int i=0;i<(1<<m);i++)
		{
			sum=(sum+dp[n][i])%Mod;
		}
		printf("%lld",sum);
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值