力求写一篇全网最详细的插头dp

模板:URAL-1519 已搬运到洛谷上 P5056

题目大意

给出n*m的方格,有些格子不能铺线,其它格子必须铺,形成一个闭合回路。问有多少种铺法?n,m(2<=n,m<=12)

插头dp:是一种基于连通性状态压缩的动态规划问题,概念性知识就不讲了,直接来做吧!

状态:

此题面对一种状态,只考虑上方(我们叫它下插头)和左方(我们叫它右插头)插头情况

如果您暂时不懂插头的含义,慢慢来看下去

$b1$、$b2$分别表示插头状态,我们知道一条线,是有左端点和右端点的,0表示无插头,1表示左端点,2表示右端点

来看这副图,在$(3,4)$的轮廓线上此时有四个插头,用括号表示法状态:(##)(##),用四进制表示法状态:$10021002$

 

   当前点不能走,只有一种状态

  $(1)$则$!b1$  $!b2$才能产生状态转移,有插头就代表会走到该点,

            不能走当然得上面没有插头,这里就不放图了,脑补$qwq$

   当前点能走

  $(1)$ $!b1$  $!b2$,则要加两个插头确保该点走过  只有以前的图了,以后再补上,将就看吧

     

     $(2)$ $!b1$ $b2$ 则向下延伸,直走或往右拐

        $(3)$ $b1$ $!b2$则向右延伸,直走或向下拐

  

     $(4)$ $b1==1$ $b2==1$ 发现了吗?这里合并后并非直接删去插头即可

               得$O(m)$往右扫找另一边匹配的右括号,让两个右括号匹配 只有以前的图了,以后再补上,将就看吧

   

    $(5)$ $b1==2$ $b2==2$  和上面一样$O(m)$往左扫找另一边的左括号,让两个左括号匹配,脑补吧$qwq$

   $ (6)$ $b1==1$ $b2==1$  直接删掉插头就好了,两边的插头会自动匹配

      

      $(7)$ $b1==2$ $b2==1$  如出现这种状态,则达到了最终闭合状态,如果当前点为终点,更新答案,否则状态不合法

        

        本题利用$hash$和滚动节省空间,为方便与快捷用位运算实现四进制,具体细节看代码

  My complete code: 

#include<cstdio>
#include<cstring>
using namespace std;
typedef long long LL;
const LL maxn=13;
const LL hs=299987;
LL n,m,ex,ey,now,last,ans;
LL a[maxn][maxn],head[300000],next[2<<24],que[2][2<<24],val[2][2<<24],cnt[2],inc[13];
inline void init(){
    scanf("%lld%lld",&n,&m);
    for(LL i=1;i<=n;++i){
        char s[100];
        scanf(" %s",s+1);
        for(LL j=1;j<=m;++j){
            if(s[j]=='.'){
                a[i][j]=1;
                ex=i; ey=j;
            }
        }
    }
    inc[0]=1;
    for(LL i=1;i<=13;++i)
        inc[i]=inc[i-1]<<2;
}
inline void insert(LL bit,LL num){
    LL u=bit%hs+1;
    for(LL i=head[u];i;i=next[i]){
        if(que[now][i]==bit){
            val[now][i]+=num;
            return;
        }
    }
    next[++cnt[now]]=head[u];
    head[u]=cnt[now];
    que[now][cnt[now]]=bit;
    val[now][cnt[now]]=num;
}
inline void work(){
    cnt[now]=1; val[now][1]=1; que[now][1]=0;
    for(LL i=1;i<=n;++i){
        for(LL j=1;j<=cnt[now];++j)
            que[now][j]<<=2;
        for(LL j=1;j<=m;++j){
            memset(head,0,sizeof(head));
            last=now; now^=1;
            cnt[now]=0;
            for(LL k=1;k<=cnt[last];++k){
                LL bit=que[last][k],num=val[last][k];
                LL b1=(bit>>((j-1)*2))%4,b2=(bit>>(j*2))%4;
                if(!a[i][j]){
                    if(!b1&&!b2)
                        insert(bit,num);
                }else if(!b1&&!b2){
                    if(a[i+1][j]&&a[i][j+1])
                        insert(bit+inc[j-1]+inc[j]*2,num);
                }else if(!b1&&b2){
                    if(a[i][j+1])
                        insert(bit,num);
                    if(a[i+1][j])
                        insert(bit-inc[j]*b2+inc[j-1]*b2,num);
                }else if(b1&&!b2){
                    if(a[i+1][j])
                        insert(bit,num);
                    if(a[i][j+1])
                        insert(bit-inc[j-1]*b1+inc[j]*b1,num);
                }else if(b1==1&&b2==1){
                    LL k1=1;
                    for(LL l=j+1;l<=m;++l){
                        if((bit>>(l*2))%4==1)
                            ++k1;
                        if((bit>>(l*2))%4==2)
                            --k1;
                        if(!k1){
                            insert(bit-inc[j]-inc[j-1]-inc[l],num);
                            break;
                        }
                    }
                }else if(b1==2&&b2==2){
                    LL k1=1;
                    for(LL l=j-2;l>=0;--l){
                        if((bit>>(l*2))%4==1)
                            --k1;
                        if((bit>>(l*2))%4==2)
                            ++k1;
                        if(!k1){
                            insert(bit-inc[j]*2-inc[j-1]*2+inc[l],num);
                            break;
                        }
                    }
                }else if(b1==2&&b2==1){
                    insert(bit-inc[j-1]*2-inc[j],num);
                }else if(i==ex&&j==ey){
                    ans+=num;
                }
            }
        }
    }
}
int main(){
    init();
    work();
    printf("%lld",ans);
    return 0;
}

  

猜你喜欢

转载自www.cnblogs.com/y2823774827y/p/10086502.html
今日推荐