51nod1683 最短路

来源:互联网 发布:txt语音朗读软件 编辑:程序博客网 时间:2024/06/10 05:01

因为不能往回走而且行数很少,可以按照列来转移。直接O(nm)记录距离显然是不可以的,但是发现相邻格子的最短路最多差1,因此我们只需要记录第1行的最短路和下面每一行和上一行的差【可以用三进制数记录】,每次转移的时候枚举下一列的01状态。转移的时候需要O(n)求最短路,可以预处理。
复杂度O(6nm2)

#include<cstdio>#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],ans[maxm],f[maxn],tem[maxn],dis[maxn],quex[2][300000],quey[2][300000],n,m,p;void inc(int &x,int y){    x+=y;    x=(x>=p?x-p:x);}int main(){    //freopen("a.in","r",stdin);    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]) inc(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) inc(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--;        }        inc(ans[y1],dp[m&1][y][x]);    }    for (int i=0;i<n+m;i++) printf("%d\n",ans[i]);}
原创粉丝点击