題意:John買了一塊矩形的地。他想在上面種草餵奶牛,但是有的格子比較貧瘠不能種草,我們用0表示。否則用1表示。由於奶牛不喜歡擠在一起,所以任何兩個相鄰格子不能都種上草。現在問你有多少種種草的方式。當然,不種草也算一種方式。
題解:第 i 行的第 j 中狀態由前一行決定。故枚舉第 i - 1 行中所有與 j 相容的狀態。
#include <iostream>using namespace std;#define Num 100000000#define N (1<<13)bool state[13][N]; /* state[i][j] 表示第i行可以化成狀態j,每一行的其他狀態都是由其初始狀態轉移的到得 */int dp[13][N], row[13]; /* row[i]表示第i行的初始狀態 */int Max, R, C;void calState ( int i ){for ( int k = 0; k <= Max; k++ ){ if ( ((~row[i]) & k) || (k & (k<<1)) ) /* 一開始用的是(row[i]&(~k)),沒注意到位元運算會修改掉原來的值,WR了很久 */ state[i][k] = 0;else state[i][k] = 1;}}void operDp (){int i, j, k;for ( i = 0; i <= Max; i++ ) /* 預先把第一行的值求出來 */{if ( state[1][i] )dp[1][i] = 1;}for ( i = 2; i <= R; i++ ){for ( j = 0; j <= Max; j++ ){if ( ! state[i][j] ) /* 若第i行的狀態j不存在,直接用第i行下一個狀態 */continue; for ( k = 0; k <= Max; k++ ) if ( state[i-1][k] && !(j & k) ) /* 若第i-1行的狀態k存在,且狀態k與狀態j直接不衝突,則dp[i][j]累加 */dp[i][j] += dp[i-1][k];dp[i][j] %= Num;}}}int main(){scanf("%d%d",&R,&C);Max = 1 << C;memset(state,0,sizeof(state));memset(dp,0,sizeof(dp));int i, j, flag;for ( i = 1; i <= R; i++ ){for ( j = 0; j < C; j++ ){ scanf("%d",&flag); row[i] |= ( flag << j );}calState ( i );}operDp();int ans = 0;for ( i = 0; i <= Max; i++ )ans += dp[R][i];printf("%d\n",ans % Num);return 0;}