POJ 1739 Tony's Tour

来源:互联网 发布:网络誉情内参 编辑:程序博客网 时间:2024/06/08 17:01

题意:给定n*m的带障碍格子图,求从左下角走到右下角的哈密顿路的总数。

题解:更进一步的插头DP,主要解法可以参照我的上篇日志:http://blog.csdn.net/tmeteorj/article/details/8635090。

改动之处在于单向插头,上篇中用01和10分别代表左右括号,这道题则需要加11作为单向括号(因为它在括号序列状态中是没有与之匹配的括号的)

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int MAX=10007;typedef long long LL;struct HT{    int head,hash[MAX],nxt[MAX];    LL cnt[MAX];    void init()    {        head=-1;        memset(hash,-1,sizeof(hash));        memset(nxt,-1,sizeof(nxt));        memset(cnt,0,sizeof(cnt));    }    void insert(int st,LL ct)    {        LL pos=st%MAX;        LL ad=1;        while(hash[pos]!=st&&hash[pos]!=-1)        {            pos+=ad*ad;            ad++;            if(pos>=MAX)pos%=MAX;        }        if(hash[pos]==-1)        {            hash[pos]=st;            cnt[pos]=ct;            nxt[pos]=head;            head=pos;        }        else            cnt[pos]+=ct;    }} dp[2];int n,m;char mp[14][14];int findright(int st,int pos){    int tp,p=pos;    for(int dep=1; dep!=0; p+=1)    {        tp=((st>>((m-p+1)*2))&3)%4;        switch(tp)        {        case 0:            break;        case 1:            dep++;            break;        case 2:            dep--;            break;        }        if(dep==0)            break;    }    return 3<<((m-p+1)*2);}int findleft(int st,int pos){    int tp,p=pos;    for(int dep=1; dep!=0; p-=1)    {        tp=((st>>((m-p+1)*2))&3)%4;        switch(tp)        {        case 0:            break;        case 1:            dep--;            break;        case 2:            dep++;            break;        }        if(dep==0)            break;    }    return 3<<((m-p+1)*2);}LL getans(int fg){    LL pos=0,ad=1;    while(dp[fg].hash[pos]!=0&&dp[fg].hash[pos]!=-1)    {        pos+=ad*ad;        ad++;        if(pos>=MAX)pos%=MAX;    }    if(dp[fg].hash[pos]==-1)    {        return 0ll;    }    else        return dp[fg].cnt[pos];}int main(){    while(scanf("%d%d",&n,&m),n||m)    {        for(int i=1; i<=n; i++)scanf(" %s",mp[i]+1);        int fg1=1,fg2,ex,ey;        fg1=0,fg2=1;        dp[fg2].init();        dp[fg2].insert(0,1ll);        for(int i=1; i<=n; i++)        {            fg1=!fg1;            fg2=!fg2;            dp[fg2].init();            for(int tp=dp[fg1].head; tp!=-1; tp=dp[fg1].nxt[tp])            {                if(dp[fg1].hash[tp]&3)                    continue;                dp[fg2].insert(dp[fg1].hash[tp]>>2,dp[fg1].cnt[tp]);            }            for(int j=0; j<m; j++)            {                fg1=!fg1;                fg2=!fg2;                dp[fg2].init();                int a=3<<(2*(m-j)),b=3<<(2*(m-j-1));                for(int pos=dp[fg1].head; pos!=-1; pos=dp[fg1].nxt[pos])                {                    int st=dp[fg1].hash[pos];                    LL ct=dp[fg1].cnt[pos];                    int x=((st&a)>>(2*(m-j)))%4,y=((st&b)>>(2*(m-j-1)))%4;                    if(i==n)                    {                        if(j==0)                        {                            if(y)                                dp[fg2].insert(st&(~b)|findright(st,j+3),ct);                            else                                dp[fg2].insert(st|b,ct);                            continue;                        }                        else if(j==m-1)                        {                            if((x==3||y==3)&(x!=3||y!=3))                                dp[fg2].insert(st&(~a)&(~b),ct);                            continue;                        }                    }                    if(mp[i][j+1]=='#')                    {                        if(x||y)                            continue;                        dp[fg2].insert(st,ct);                    }                    else if(x)                    {                        if(y)                        {                            if(x==1&&y==1)                                dp[fg2].insert((st&(~a)&(~b))^findright(st,j+3),ct);                            else if(x==2&&y==1)                                dp[fg2].insert(st&(~a)&(~b),ct);                            else if(x==2&&y==2)                                dp[fg2].insert((st&(~a)&(~b))^findleft(st,j),ct);                            else if(x==3)                                dp[fg2].insert((st&(~a)&(~b))|findright(st,j+3),ct);                            else if(y==3)                                dp[fg2].insert((st&(~a)&(~b))|findleft(st,j),ct);                        }                        else                        {                            dp[fg2].insert(st,ct);                            dp[fg2].insert(st&(~a)|(x<<(2*(m-j-1))),ct);                        }                    }                    else if(y)                    {                        dp[fg2].insert(st,ct);                        dp[fg2].insert(st&(~b)|(y<<(2*(m-j))),ct);                    }                    else                        dp[fg2].insert(st|(1<<(2*(m-j)))|(2<<(2*(m-j-1))),ct);                }            }        }        printf("%lld\n",getans(fg2));    }    return 0;}