1. 程式人生 > >力求寫一篇全網最詳細的插頭dp

力求寫一篇全網最詳細的插頭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;
}