POJ 3254
Time Limit: 2000MS | Memory Limit: 65536K | |
Total Submissions: 15745 | Accepted: 8275 |
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.
Source
今天刚学状压dp,碰到这个题,下午看了好几个博客,终于有了点头绪。(大佬的博客注释都比较少。。所以我写了比较多的注释)
利用二进制与十进制的关系,降低维度。像这个题,每行的土地都只有0 1两种状态,可以把这一行的状态用一个十进制数表示。这应该就是一种状态压缩了~。void getvalid()///得到所有可行的状态 { for(int i = 0 ; i < (1<<n);i++){ if(!(i&(i<<1))){///如果这个数的二进制形式没有相邻的1,会将这个数记录下来 st[num++] = i; } } }
判断理想是否符合现实(该状态所对应的各个位置是否是肥沃土地)。
bool judge(int p,int q)///判断该状态是否符合土地状况,也就是说,想种东西的地方是不是肥沃 { if(!(st[p]&map[q])){///注意:!!这里土地状态map[q]是记录的不肥沃的土地,所以按位与后应为0,取非为1 return true; /// 换句话说 想法与实践比较,前者为想法,后者为实践,看是否可行 } return false; }
接下来更详细的在代码里都有了~~
#include<iostream> #define MOD 100000000 using namespace std; int dp[13][100005];///dp[i][j]表示第i行第j状态时的方案数 int st[10009];///一行中所有的可行的状态 int num;///记录状态数 int n,m;///m行n列 int s;///暂存单位土地的状态 int map[15];///十进制数记录每行的土地状态 void getvalid()///得到所有可行的状态 { for(int i = 0 ; i < (1<<n);i++){ if(!(i&(i<<1))){///如果这个数的二进制形式没有相邻的1,会将这个数记录下来 st[num++] = i; } } } bool judge(int p,int q)///判断该状态是否符合土地状况,也就是说,想种东西的地方是不是肥沃 { if(!(st[p]&map[q])){///注意:!!这里土地状态map[q]是记录的不肥沃的土地,所以按位与后应为0,取非为1 return true; /// 换句话说 想法与实践比较,前者为想法,后者为实践,看是否可行 } return false; } int main() { cin >> m >> n; for(int i = 1 ; i <= m ; i++){ map[i] = 0; for(int j = 1 ; j <= n ; j++){ cin >> s; if(!s){ map[i] += (1<<(j-1));///将每行的不肥沃的土地记录下来 } ///注意此处是j!! } } for(int i = 0 ; i < 13;i++){ for(int j = 0 ; j < 100005;j++){ dp[i][j] = 0; } } dp[0][0] = 1;///啥也不放时,算一种方案 num = 0; getvalid(); for(int i = 1 ; i <= m;i++){ for(int j = 0; j < num ; j++){///j是这一行状态的编号 if(judge(j,i)){ for(int k = 0 ; k < num ; k++){///k是这一行的编号 if(judge(k,i-1)&&!(st[j]&st[k])){///如果上一行的k对应的状态是“理想”与“现实”相同的 & & 并且这一行状态与上一行状态之间没有出现相同位都是1 dp[i][j] += dp[i-1][k]; } } } } } int sum = 0; for(int i = 0; i < num;i++){ sum += dp[m][i]; sum %= MOD; } cout << sum << endl; return 0; }
转载请注明出处~~
感谢您的阅读~