代码参考: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;
} 

 

posted on 2018-03-04 19:57  湮灭之瞳  阅读(117)  评论(0编辑  收藏  举报