插头dp 模版

有障碍,

***。。

。。。。

求回路数量

#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
using namespace std;
typedef long long LL;
const int LIM=300005,Has=299989;
int n,m,e1,e2,las,now,tt;LL ans;
int mp[15][15],bin[15],tot[2];LL js[2][LIM];
int h[300005],a[2][LIM],ne[LIM];
//tot:状态总数,js:该状态的方案总数,a:各种状态
void ins(int zt,LL num) {//卓越的哈希技术
    int tmp=zt%Has+1;
    for(int i=h[tmp];i;i=ne[i])//h相当于一个头
        if(a[now][i]==zt)
        {
            js[now][i]+=num;//找到了对应状态
            return;
        }
    ne[++tot[now]]=h[tmp];
    h[tmp]=tot[now];//头是新的计数器,指向以前的h
    a[now][tot[now]]=zt;//把当前计数器e的状态和数量修改
    js[now][tot[now]]=num;
}

void work() {
    tot[now]=1,js[now][1]=1,a[now][1]=0;
    for(int i=1;i<=n;++i) {
        
        for(int j=1;j<=tot[now];++j)
            a[now][j]<<=2;//切换行了
        
        for(int j=1;j<=m;++j) {
            las=now,now^=1;
            memset(h,0,sizeof(h)),tot[now]=0;
            
            for(int k=1;k<=tot[las];++k) {
                int zt=a[las][k],b1=(zt>>(j*2-2))%4,b2=(zt>>(j*2))%4;//提取关键格子上的两段轮廓线状态
                
                LL num=js[las][k];
                
                if(!mp[i][j])
                {
                    if(!b1&&!b2)
                        ins(zt,num);
                }
                else if(!b1&&!b2)
                    {if(mp[i+1][j]&&mp[i][j+1]) ins(zt+bin[j-1]+2*bin[j],num);}
                else if(!b1&&b2) {
                    if(mp[i][j+1]) ins(zt,num);
                    if(mp[i+1][j]) ins(zt-bin[j]*b2+bin[j-1]*b2,num);
                }
                else if(b1&&!b2) {
                    if(mp[i][j+1]) ins(zt-bin[j-1]*b1+bin[j]*b1,num);
                    if(mp[i+1][j]) ins(zt,num);
                }
                else if(b1==1&&b2==1) {
                    int kl=1;
                    for(int t=j+1;t<=m;++t) {
                        if((zt>>(t*2))%4==1) ++kl;
                        if((zt>>(t*2))%4==2) --kl;
                        if(!kl) {ins(zt-bin[j]-bin[j-1]-bin[t],num);break;}
                    }
                }
                else if(b1==2&&b2==2) {
                    int kl=1;
                    for(int t=j-2;t>=0;--t) {
                        if((zt>>(t*2))%4==1) --kl;
                        if((zt>>(t*2))%4==2) ++kl;
                        if(!kl) {ins(zt+bin[t]-2*bin[j]-2*bin[j-1],num);break;}
                    }
                }
                else if(b1==2&&b2==1)
                    ins(zt-2*bin[j-1]-bin[j],num);
                else if(i==e1&&j==e2)
                    ans+=num;
            }
        }
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j) {
        char ch=getchar();
        while(ch!='*'&&ch!='.') ch=getchar();
        if(ch=='.') mp[i][j]=1,e1=i,e2=j;
    }
    bin[0]=1;for(int i=1;i<=12;++i) bin[i]=bin[i-1]<<2;
    work(),printf("%lld\n",ans);
    return 0;
}

 

posted @ 2020-06-01 11:44  Faker_fan  阅读(150)  评论(0编辑  收藏  举报