poj 3254 Corn Fields (状压DP入门)
Time Limit: 2000MS | Memory Limit: 65536K | |
Total Submissions: 20694 | Accepted: 10855 |
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
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.
题目大意:
用一个最大12x12的01矩阵表示土地,1表示这块土地肥沃,0表示这块土地贫瘠。肥沃的土地可以用来种草放牧。
但是牛喜欢独自占领一块地的感觉,所以你选择种草的土地不能是相连的。
如果不考虑一共在多少块土地上种草,问你一共有多少种种植方案。不种植也算一种方案。
摘抄一下BlackStorm的cnblog(%%%),我基本就是按照他的方式处理的:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> #include<queue> #include<cstring> #include<algorithm> typedef long long lol;//宏定义上线 using namespace std; const int maxn=12; const int mod=100000000; int sat[400];//满足条件的状态(左移与为0),经验证本题只需要前400个 int row[maxn+5];//每行的草地状态 lol dp[maxn+5][400];//dp[i][j]表示第i行采用第j种状态可以有多少种方式 int main() { for(int i=0,j=1;i<=(1<<maxn);i++)//首先满足自身相邻不都为1 { if((i&(i<<1))==0) sat[j++]=i; } //for(int i=1;sat[i]<(1<<maxn);i++) printf("%d\n",sat[i]); int m,n; while(scanf("%d%d",&m,&n)!=EOF) { for(int i=1,temp;i<=m;i++) { temp=0; for(int j=1,a;j<=n;j++) { scanf("%d",&a); //反转 if(a==1) a=0; else a=1; temp=((temp<<1)|a); } row[i]=temp; } memset(dp,0,sizeof(dp)); //第一行 for(int i=1;sat[i]<(1<<n);i++) { if((sat[i]&row[1])==0) dp[1][i]=1; } //按行递推 for(int i=2;i<=m;i++) { for(int j=1;sat[j]<(1<<n);j++) { if((sat[j]&row[i])==0)//选择的状态与本行的草地不冲突 { for(int k=1;sat[k]<(1<<n);k++) { if((sat[k]&sat[j])==0)//与上一行的状态不冲突 dp[i][j]+=dp[i-1][k]; } } } } lol ans=0; for(int i=1;sat[i]<(1<<n);i++) ans=(ans+dp[m][i])%mod;//注意取模 printf("%lld\n",ans); } return 0; }