插头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; }