Poj3254 Corn Fields (状压Dp)

来源:互联网 发布:java 生成pdf表格 编辑:程序博客网 时间:2024/05/20 06:25

传送门Time Limit: 2000MS Memory Limit: 65536K

Description

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的矩阵(n,m<=12),每个边长为一的小矩阵视为一块草地,草地有肥沃(1)与贫瘠(0)之分

然后现在有INF的牛(我编的,其实就是无限只)需要放在肥沃的草地上吃草

相邻的两块草地上不能同时有牛,问有多少种方法放牛,答案最后对100,000,000取模

思路

如果用坐标性Dp,那么按照习惯我们就要定义一个

f[行数][该行第一个位置的状态][该行第二个位置的状态]……[该行第12个位置的状态]

总计13个下标的大数组,显然我们处理起来会很麻烦,这时候我们就应该要优化一下

我们可以看到m的范围其实很小,而如果有一个范围是在20以内,并且是一个Dp问题的话

我们不难想到状压Dp,状压Dp的实质就是通过二进制数对其进行优化

最好先去学一下位运算不然很难看懂后面的代码

例如样例中的1 1 1 / 0 1 0 我们就可以用二进制数 111/010 (即7与2) 来表示

为了方便后面的计算我对其进行了取反的处理,就变成了 000/101 (即0与5)

这样用二进制数把图一行一行的存储就能将原 f 数组后面12维压缩成一维

当然还想优化空间也可以使用滚动数组(可我这种懒人不想写

其实方程本来也就不难想主要是看怎么去把数组优化

所以我就不说状态转移方程怎么推了自己推一下吧

代码

#include<cstdio>#include<cstring>using namespace std;const int Mod=100000000;int n,m,k,ans,x;int map[15],st[5000],f[15][5000];void init(){    k=0,ans=0;    memset(map,0,sizeof(map));    memset(f,0,sizeof f);    memset(st,0,sizeof st); } int main(){    while(scanf("%d%d",&n,&m)!=EOF) //有多组数据     {        init();//记得初始化数组与变量         for(int i=1;i<=n;i++)         for(int j=1;j<=m;j++)         {            scanf("%d",&x);            if(x==0) map[i]+=1<<(j-1); //读入处理             //用来存地图(一行一行地存)并取反          }        for(int i=0;i<(1<<m);i++)         if(!(i&(i<<1))) st[++k]=i;    //判断是否相邻,找到可行的情况         for(int i=1;i<=k;i++)         if(!(map[1]&st[i])) f[1][st[i]]=1; //初始化第一行         for(int i=2;i<=n;i++)         for(int j=1;j<=k;j++)         {            if(st[j]&map[i]) continue;            for(int l=1;l<=k;l++)             {                if(st[l]&map[i-1]) continue;                if(!(st[l]&st[j])) f[i][st[j]]+=f[i-1][st[l]];             }         }        for(int i=1;i<=k;i++)         ans=(ans+f[n][st[i]])%Mod;        printf("%d",ans);    }       return 0;}
原创粉丝点击