POJ 1739 Tony's Tour

版权声明:写得不好,转载请通知一声,还请注明出处,感激不尽 https://blog.csdn.net/As_A_Kid/article/details/81974039

Problem

POJ

Solution

珍惜生命,远离插头DP。
不得不说拿这道题做为插头DP入门题真是很不友好啊。

问从左下角遍历到右下角的方案数。
考虑再加两行,加的第一行仅第一格和最后一格无障碍,第二行都无障碍。那么这道题又变成了一个求一条简单回路遍历整个棋盘的题。

那么就是维护括号序列,考虑用三进制来储存状态,2表示( ,3表示)。当然了,你也可以用四进制用位运算搞一搞。
你以为这样就完了吗?开完数组你就会发现MLE了。这道题的状态数很大,但其实真正用到的却不多,那么你得要用滚动数组,然后再把所有不为零的状态丢到队列里去就可以快很多,hash好像也可以。细节挺多的,而且插头DP的调试难度也比较大。

Code

#include <cstring>
#include <cstdio>
#include <queue>
#define rg register
using namespace std;
typedef long long ll;
const int maxn=200010,INF=0x3f3f3f3f;
template <typename Tp> inline int getmin(Tp &x,Tp y){return y<x?x=y,1:0;}
template <typename Tp> inline int getmax(Tp &x,Tp y){return y>x?x=y,1:0;}
template <typename Tp> inline void read(Tp &x)
{
    x=0;char ch=getchar();int f=0;
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-') f=1,ch=getchar();
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    if(f) x=-x;
}
struct data{int p,s;}t;
int n,m,x,y,end,a[15][15],cd[15],dfn[2][maxn];
ll now,ans,f[2][maxn];
char s[15];
queue<data> q;
int input()
{
    if(scanf("%d",&n)==EOF) return 0;
    read(m);
    if(!n&&!m) return 0;
    memset(a,0,sizeof(a));
    memset(dfn,0,sizeof(dfn));
    memset(f,0,sizeof(f));
    for(rg int i=1;i<=n;i++)
    {
        scanf("%s",s+1);
        for(rg int j=1;j<=m;j++)
          a[j][n-i+3]=(s[j]=='.');
    }
    n+=2;ans=0;a[1][2]=a[m][2]=1;end=n*m-1;
    for(rg int i=1;i<=m;i++) a[i][1]=1;
    while(!a[end%m+1][end/m+1]) end--;
    return 1;
}
int hash(int x,int v1,int v2)
{
    int res=0;
    for(rg int i=m+1;i;i--)
    {
        res=res*3;
        if(i==x) res+=v1;
        else if(i==x+1) res+=v2;
        else res+=cd[i];
    }
    return res;
}
void update(int p,int s,ll add)
{
    p++;
    if(dfn[p&1][s]^p) dfn[p&1][s]=p,f[p&1][s]=0,q.push((data){p,s});
    f[p&1][s]+=add;
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    #endif
    while(input())
    {
        f[0][0]=dfn[0][0]=1;q.push((data){0,0});
        while(!q.empty())
        {
            t=q.front();q.pop();now=f[t.p&1][t.s];
            if(t.p%m==0) t.s*=3;
            x=t.p%m+1;y=t.p/m+1;
            memset(cd,0,sizeof(cd));
            for(rg int i=1,j=t.s;j;i++,j/=3) cd[i]=j%3;
            if(!a[x][y]) update(t.p,hash(x,0,0),now);
            else if(cd[x]==1&&cd[x+1]==2){if(t.p==end) ans+=now;}
            else if(cd[x]==2&&cd[x+1]==1) update(t.p,hash(x,0,0),now);
            else if(cd[x]==0&&cd[x+1]==0){if(a[x][y+1]&&a[x+1][y]) update(t.p,hash(x,1,2),now);}
            else if(cd[x]==0)
            {
                if(a[x+1][y]) update(t.p,hash(x,0,cd[x+1]),now);
                if(a[x][y+1]) update(t.p,hash(x,cd[x+1],0),now);
            }
            else if(cd[x+1]==0)
            {
                if(a[x+1][y]) update(t.p,hash(x,0,cd[x]),now);
                if(a[x][y+1]) update(t.p,hash(x,cd[x],0),now);
            }
            else if(cd[x]==cd[x+1])
            {
                int p1=0,p2=0;
                if(cd[x]==1)
                {
                    for(rg int i=x+2,j=0;i<=m;i++)
                    {
                        if(cd[i]==1) j--;
                        if(cd[i]==2) j++;
                        if(j>0&&!p1) p1=i,j--;
                        if(j>0&&p1){p2=i;break;}
                    }
                }
                else
                {
                    for(rg int i=x-1,j=0;i;i--)
                    {
                        if(cd[i]==1) j++;
                        if(cd[i]==2) j--;
                        if(j>0&&!p2) p2=i,j--;
                        if(j>0&&p2){p1=i;break;}
                    }
                }
                cd[p1]=1;cd[p2]=2;update(t.p,hash(x,0,0),now);
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/As_A_Kid/article/details/81974039
今日推荐