第一道自己写的状态压缩DP. 题意是在一个二维矩阵中选一些数,这些数不能相邻,有多少种选法. 因为每行的可行状态只与上一行有关,所以只要预先计算两行的可行放置方案,再进行状态转移就可以了 #include <iostream> #define MODULE 100000000 #define MAXN 100010 using namespace std ; int n , m , ntrans ; int trans[2][48000] , state[400] , corn[14] , cnt[14][1 << 12] ; void Read () { int i , j , t , k ; scanf ("%d%d" , &n , &m) ; memset (corn , 0 , sizeof (corn)) ; for (i = 1 ; i <= n ; i ++) { for (t = j = 0 ; j < m ; j ++) { scanf ("%d" , &k) ; t |= k << j ; } corn[i] = t ;//用二进制表示各行的状态 } } void CalState () { int i , a[4096] , j , k ; for (k = 0 , i = 0 ; i < (1 << m) ; i ++) { for (j = 1 ; j < (1 << (m - 1)) ; j <<= 1) if ((i & j) && (i & (j << 1))) break ; if (j >= (1 << (m - 1))) state[k ++] = i ;//state记录单行合法的放置方案,用二进制1表示放置,0表示不放 } for (ntrans = i = 0 ; i < k ; i ++) for (j = 0 ; j < k ; j ++) if ((state[i] & state[j]) == 0) { trans[0][ntrans] = state[i] ; trans[1][ntrans ++] = state[j] ;//trans记录两行的合法放置方案, } } void Solve () { int i , j , ans = 0 ; memset (cnt , 0 , sizeof (cnt)) ; cnt[0][0] = 1 ; for (i = 1 ; i <= n ; i ++) for (j = 0 ; j < ntrans; j ++) if ((trans[0][j] | corn[i - 1]) == corn[i - 1] && (trans[1][j] | corn[i]) == corn[i])//trans[0][j]这个方案在第i-1行是可行的,trans[1][j]这个方案在第i行可行 cnt[i][trans[1][j]] = (cnt[i][trans[1][j]] + cnt[i - 1][trans[0][j]]) % MODULE ; for (j = 0 ; j < ntrans ; j ++) ans = (ans + cnt[n][j]) % MODULE ; printf ("%d/n" , ans) ; } int main () { Read () ; CalState () ; Solve () ; return 0 ; }