题意:在m*n的矩阵上,1表示能放牛,0表示不能放。要求放的牛不能相邻(上下相邻或者左右相领),问放牛的方法种数。
解法:设d[i][j]表示第i行状态为j的情况下,能放的牛的数量。d[i][j] += d[i-1][k],其中k表示能转移到j的状态,num(j)表示状态为j的行所放的牛的数量。当然,还要判断一下状态j是不是能放在第i行。
tag:状压dp
1 /* 2 * Author: Plumrain 3 * Created Time: 2013-11-18 23:37 4 * File Name: DP-POJ-3254.cpp 5 */ 6 #include <iostream> 7 #include <cstdio> 8 #include <cstring> 9 10 using namespace std; 11 12 #define CLR(x) memset(x, 0, sizeof(x)) 13 const int mod = 100000000; 14 15 int n, m, a[20][20]; 16 int d[20][1<<13]; 17 18 void init() 19 { 20 for (int i = 0; i < n; ++ i) 21 for (int j = 0; j < m; ++ j) 22 scanf ("%d", &a[i][j]); 23 } 24 25 bool gao1(int sta) 26 { 27 int x = 0; 28 while (sta > 0){ 29 if (x == 1 && (sta&1)) 30 return 0; 31 x = sta & 1; 32 sta >>= 1; 33 } 34 return 1; 35 } 36 37 bool gao2(int sta, int k) 38 { 39 for (int i = 0; i < m; ++ i) 40 if (!a[k][i] && (sta & (1<<i))) return 0; 41 return 1; 42 } 43 44 bool gao3(int s1, int s2) 45 { 46 for (int i = 0; i < (1<<m); ++ i){ 47 int t1 = s1 & (1<<i), t2 = s2 & (1<<i); 48 if (t1 && t2) return 0; 49 } 50 return 1; 51 } 52 53 int DP() 54 { 55 CLR (d); 56 for (int i = 0; i < (1<<m); ++ i) 57 if (gao1(i) && gao2(i, 0)) d[0][i] = 1; 58 59 for (int i = 1; i < n; ++ i) 60 for (int j = 0; j < (1<<m); ++ j){ 61 d[i][j] = 0; 62 if (gao1(j) && gao2(j, i)) 63 for (int k = 0; k < (1<<m); ++ k) 64 if (gao3(j, k)) d[i][j] = (d[i][j] + d[i-1][k]) % mod; 65 } 66 67 int ret = 0; 68 for (int i = 0; i < (1<<m); ++ i) 69 if (gao1(i) && gao2(i, n-1)) ret = (d[n-1][i] + ret) % mod; 70 return (int)ret; 71 } 72 73 int main() 74 { 75 while (scanf ("%d%d", &n, &m) != EOF){ 76 init(); 77 printf ("%d ", DP()); 78 } 79 return 0; 80 }