每一个点可向上下左右四个方向连边,这就是插头。
每一条轮廓线切开的是当前已确定的点的未确定的点,其经过的插头有m个竖着的,一个横着的,懒得画图了。。
每一次转移就是将左边的变到下面,上面的变到左边,每一行转移直接左移一位。
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; int a[13][13],n,m,bit[15]; long long f[13][13][1<<13]; void dp(){ memset(f,0,sizeof f); f[0][m][0]=1; for(int i=1;i<=n;i++){ for(int j=0;j<bit[m];j++) if(f[i-1][m][j]) f[i][0][(j<<1)]=f[i-1][m][j]; for(int j=1;j<=m;j++){ for(int k=0;k<bit[m+1];k++){ if(a[i][j]){ if((k&bit[j])&&(k&bit[j-1])) f[i][j][k]=f[i][j-1][k^bit[j]^bit[j-1]]; else if((!(k&bit[j]))&&(!(k&bit[j-1]))) f[i][j][k]=f[i][j-1][k^bit[j]^bit[j-1]]; else f[i][j][k]=f[i][j-1][k^bit[j]^bit[j-1]]+f[i][j-1][k]; } else{ if((!(k&bit[j]))&&(!(k&bit[j-1]))) f[i][j][k]=f[i][j-1][k]; else f[i][j][k]=0; } } } } printf("There are %lld ways to eat the trees. ",f[n][m][0]); } int main(){ int T; scanf("%d",&T); bit[0]=1; for(int i=1;i<=13;i++) bit[i]=bit[i-1]<<1; for(int t=1;t<=T;t++){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d",&a[i][j]); printf("Case %d: ",t); dp(); } }