Time Limit: 2000MS | Memory Limit: 65536K | |
Total Submissions: 8138 | Accepted: 4339 |
Description
Farmer John has purchased a lush new rectangular pasture composed of M byN (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
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
Sample Input
2 3 1 1 1 0 1 0
Sample Output
9
Hint
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的小块,其中有的小块可以放牛,有的不可以,题目中给出,同一小块只能放一种牛,且相邻的草地放得牛的种类不同,文一共有多少中放牛的方案。(注意结果mod1e8);
至于和状态DP有关,别人说如果n,m之类的范围在32之内,等比较小得数时,可以考虑一下状态DP。我认为状态dP就是把题目中的给出条件变为各个状态,动态规划递归求解。当然难点在于怎么把状态构造出来。只有找到合适的状态才能巧妙的运用上这个。
由于对于位运算的不熟悉,导致了好多wa,注意 (1<<m-1)和((1<<m)-1)是不一样的。
对于这个题,相对简单(不过我做了好长时间,O__O"…,渣爆了)。只要记录每一行的状态即可;
dp[i][k]表示第i行状态为k的时候的可行的方案数,状态转移方程为dp[i][k]=∑(dp[i-1][s]);
代码:
#include <iostream>
#include <string.h>
#include <stdio.h>
#define N 13
#define M 1<<13
#define mod 100000000
using namespace std;
int a[N];
long long dp[N][M];
int check1(int x)///检查是否有相邻的放相同种类的牛
{
return !((x>>1)&x);//左移或右移后按位与
}
int check2(int x,int y)//判断两行的状态有没有上下相邻且种类相同的
{
return !(x&y);//按位与
}
int check(int a,int x,int m)//检查有没有不能放缺放了的
{
return !(x&(~a));//将a取反和x按位与
}
void slove(int n,int m)
{
long long statue=1<<m;///2^m次方个状态
int i,j,k;
memset(dp,0,sizeof(dp));
for(i=0; i<=statue; i++)//初始化
{
if(check(a[1],i,m)&&check1(i))
dp[1][i]=1;
}
for(i=2; i<=n; i++)
{
for(j=0; j<=statue; j++)
{
if(check1(j)&&check(a[i],j,m))
{
for(k=0; k<=statue; k++)
{
if(check2(j,k))
dp[i][j]=(dp[i][j]%mod+dp[i-1][k]%mod)%mod;
}
}
}
}
}
int main()
{
int n,m,i,j,x;
long long ans;
while(~scanf("%d%d",&n,&m))
{
ans=0;
long long statue=1<<m;
for(i=1; i<=n; i++)
{
for(j=1; j<=m; j++)
{
scanf("%d",&x);
a[i]=(a[i]<<1)+x;///压缩为二进制数
}
}
slove(n,m);
for(i=0; i<=statue; i++)//将最后一行的数求和
ans=(ans%mod+dp[n][i]%mod)%mod;
printf("%I64d\n",ans);
}
return 0;
}