http://poj.org/problem?id=3254
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
Output
Sample Input
2 3 1 1 1 0 1 0
Sample Output
9
Hint
1 2 3 4
本题题目大意:在一个n*m的棋盘里放棋子,其中哪些位置可以放哪些位置不可以放已知,并且要求在放棋子的时候上下左右不能有棋子相邻。求一共有多少种方法可以完成该任务。
解题思路:
一开始想着用搜索写,和网络赛的那个题一样无休止的TLE,后来才知道了状态压缩的写法。先预处理那些位置是不能放的,然后枚举状态,刨去有相邻的,不该放的位置放的。然后状态转移:dp[ i ] [ j ] = dp[ i ][j]+dp[k][j-1];i,k分别代表枚举的合法的状态,j表示第几行。边界问题:j=0 时所有满足条件的状态为1,不满足的为0。
#include <stdio.h> #include <iostream> #include <string.h> #include <algorithm> using namespace std; typedef long long LL; const int MOD=100000000; const int N=(1<<13)+10; int forbid[N],way[N],dp[N][15]; int n,m,top; bool judge1(int x)//如果有相邻1的则排除。 { if(x&(x<<1)) return false; return true; } bool judge2(int x,int i)//如果有不能放的位置 { if(x&forbid[i])return false; return true; } void init() { memset(dp,0,sizeof(dp)); top=0; for(int i=0; i<(1<<m); i++) if(judge1(i)) way[top++]=i; } int main() { while(~scanf("%d%d",&n,&m)) { for(int i=0; i<n; i++) { forbid[i]=0; for(int j=0; j<m; j++) { int x; scanf("%d",&x); if(x==0) forbid[i]|=1<<j; } } init(); for(int i=0; i<top; i++) if(judge2(way[i],0))dp[way[i]][0]=1; for(int i=1; i<n; i++) for(int j=0; j<top; j++) { if(!judge2(way[j],i))continue; for(int k=0; k<top; k++) if(judge2(way[k],i-1)&&!(way[k]&way[j]))//k与j下一步会是上下相邻的两行,不能在同一位上为均为1 dp[way[j]][i]=(dp[way[j]][i]+dp[way[k]][i-1])%MOD; } int ans=0; for(int i=0; i<top; i++) ans=(ans+dp[way[i]][n-1])%MOD; printf("%d\n",ans); } return 0; }