您的位置:首页 > 其它

Corn Fields POJ - 3254(状态压缩dp入门)

2017-07-06 12:37 344 查看
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.

这是第一道我做的状态压缩的dp题,谈谈感受,状态压缩和位运算有关,所以位运算的能力是基础,我觉得压缩的意思就是,用一个数字来表示多个信息,而这个多种信息就综合成一个状态,如果将这多个信息线性排列,然后每一个位置用一个数字表示某种信息,那么可以发现我们可以把这一列的数和合并成整体,如果要表示n个信息,那么就可以看成一个n位的某种进制的数,如果信息的种类就只有两个,如这道题,只存在放和不放牛,那么我们完全就可以用二进制,并且c++里存在对位运算的直接操作,如果是大于2中,那就需要另外的解码(decode)和编码(encode)的操作了。

题目代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define mod 100000000
using namespace std;
int state[1<<13],mapp[20];//把一行的信息都压缩到成一个数字,state来存放所有合法的状态,比如1111,就是不合法的,首先在行里就是不允许有相邻放牛
int dp[13][1<<13];//就是说以第i层是以状态j这种情况放置的所有的种数
bool judge(int i)
{
return i&(i<<1);
}
bool judge2(int i,int x)
{
return mapp[i]&state[x];
}
int main()
{
int n,m;
int x;
memset(mapp,0,sizeof(mapp));
scanf("%d%d",&m,&n);
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
{
scanf("%d",&x);
if(x==0)
mapp[i]+=(1<<(n-j));
}

int k=0;
for(int i=0;i<(1<<n);i++)
{
if(!judge(i))
state[k++]=i;//首先将状态做了第一步筛选,至少行里不能存在有相邻的,存到state里,
}

memset(dp,0,sizeof(dp));
for(int i=0;i<k;i++)
{
if(!judge2(1,i))//合法以后并且也要满足地图的状态,因为地图里有些地方放不了牛
dp[1][i]=1;
}

for(int i=2;i<=m;i++)
{
for(int j=0;j<k;j++)
{
if(judge2(i,j))//找一个可以递推的下一个合法状态
continue;
for(int l=0;l<k;l++)
{
if(judge2(i-1,l))//找一个可以递推给dp[i][j]的一个状态
continue;
if(!(state[j]&state[l]))//最后还要满足列上不能有相邻的放牛的情况
dp[i][j]+=dp[i-1][l];
}
}
}
int ans=0;
for(int i=0;i<k;i++)
ans=(ans+dp[m][i])%mod;
printf("%d",ans);//最后加起来即可
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: