状态DP
二进制题型,用0和1来确定所有的情况。
把每一行安排的情况看成一个二进制数,如果这一行的某一列安排了一头奶牛,那么对应的二进制就是1,如果没有安排那么就是0.如果某个状态表示里出现了两个连续的1,那么这个状态永远是非法的,可以去掉,这样处理之后剩下的可能合法。
令dp[i][j]表示第i行状态为j时有多少可能的安排方法,那么状态转移方程是:如果j是合法状态:dp[i][j]=sum{dp[i-1][k]},其中满足k&j==0。
#include<stdio.h> #include<string.h> #define maxn (1<<13) #define mod 100000000 int n,m; int dp[15][maxn]; bool flag[15][maxn]; int mat[15]; int mm; void init() { for(int i=1;i<=n;i++) for(int j=0;j<=mm;j++) { flag[i][j]=true; if((~mat[i]&j)||(j&(j<<1))) flag[i][j]=false; } } int main() { while(scanf("%d%d",&n,&m)!=EOF) { memset(dp,0,sizeof(dp)); memset(mat,0,sizeof(mat)); int num; for(int i=1;i<=n;i++) for(int j=m-1;j>=0;j--) { scanf("%d",&num); if(num==1)mat[i]|=(1<<j); } mm=(1<<m)-1; init(); for(int i=0;i<=mm;i++) if(flag[n][i]) dp[n][i]=1; int i,j; for(i=n-1;i>=1;i--) { for(j=0;j<=mm;j++) { if(!flag[i][j]) continue; for(int k=0;k<=mm;k++) { if(!flag[i+1][k]) continue; if(!(j&k)) dp[i][j]+=dp[i+1][k]; } dp[i][j]%=mod; } } int ans=0; for(i=0;i<=mm;i++) ans+=dp[1][i]%mod; ans%=mod; printf("%d ",ans); } }