代码参考:http://blog.csdn.net/sdfzyhx/article/details/74359927
//dp[i][j][k]表示到了第i列,最下边的点最短路为j,剩下的点之间的关系为k的方案; //只需知道这一行的棋盘状态和上一行的最短路之间的相对关系(1,0,-1)即可完成转移; #include<iostream> #include<cstring> #include<cstdio> #include<cmath> #include<algorithm> using namespace std; const int max4=1050,max2=70,maxm=110,maxn=10; int transx[max4][max2],transy[max4][max2],dp[2][maxm][max4],last[2][maxm][max4]; int ans[maxm],f[maxn],tem[maxn],dis[maxn],quex[2][300000],quey[2][300000],n,m,p; void update(int &x,int y){ x+=y; x=(x>=p?x-p:x); } int main(){ int x,y,x1,y1,ok,tl[2]; scanf("%d%d%d",&n,&m,&p); //预处理转移数组; for(int s=0;s<(1<<(2*(n-1)));++s){//上一行的最短路情况; ok=1; for(int i=1;i<n;++i){ x=(s>>((i-1)*2))&3; if(x==2){ok=0;break;} if(x){ if(x==1)f[i]=f[i-1]+1; else f[i]=f[i-1]-1; } else f[i]=f[i-1]; } if(!ok)continue; for(int t=0;t<(1<<n);++t){//这一行的棋盘情况; for(int i=0;i<n;++i)tem[i]=(t>>i)&1; dis[0]=f[0]+tem[0]; for(int i=1;i<n;++i)dis[i]=min(dis[i-1],f[i])+tem[i]; for(int i=n-2;i>=0;--i)dis[i]=min(dis[i],dis[i+1]+tem[i]); transy[s][t]=dis[0]; for(int i=1;i<n;++i){ if(dis[i]==dis[i-1])x=0; else if(dis[i]==dis[i-1]+1)x=1; else x=3; transx[s][t]|=x<<(2*(i-1)); } } } //处理初始态; for(int t=0;t<(1<<n);++t){ x=0; for(int i=1;i<n;++i)if((t>>i)&1)x|=1<<(2*(i-1)); y=t&1; if(last[1][y][x])update(dp[1][y][x],1); else{ last[1][y][x]=1; dp[1][y][x]=1; tl[1]++; quex[1][tl[1]]=x; quey[1][tl[1]]=y; } } //转移 for(int i=2,c=0;i<=m;++i,c^=1){ tl[c]=0; for(int j=1;j<=tl[c^1];++j){ x=quex[c^1][j]; y=quey[c^1][j]; for(int t=0;t<(1<<n);++t){ x1=transx[x][t]; y1=y+transy[x][t]; if(last[c][y1][x1]==i)update(dp[c][y1][x1],dp[c^1][y][x]); else{ last[c][y1][x1]=i; dp[c][y1][x1]=dp[c^1][y][x]; tl[c]++; quex[c][tl[c]]=x1; quey[c][tl[c]]=y1; } } } } //统计答案 for(int j=1;j<=tl[m&1];++j){ x=quex[m&1][j]; y1=y=quey[m&1][j]; for(int i=1;i<n;++i){ x1=(x>>(2*(i-1)))&3; if(x1==1)y1++; else if(x1==3)y1--; } update(ans[y1],dp[m&1][y][x]); } for(int i=0;i<n+m;++i)printf("%d\n",ans[i]); return 0; }