pd head plug
purpose
Plug dp is mainly used to solve the dynamic programming problem based on connectivity state compression. Generally speaking, it is to solve the problem of the number of loop schemes in a grid graph, and the data range is small, such as This template
method
Define plug: whether the path passes through the edge of the grid point. As shown in the figure, it is a left plug
It is not difficult to find that there are only two plugs for all points on a circuit, as shown in the figure
So I will pop search \ (\ Theta(6^{nm}) \)
This is obviously unrealistic. Consider dp transfer
Transferred object
Consider the transfer contour, that is, a line that separates the semi graph we have considered and the semi graph we have not considered, such as the green line in the figure, and the blue line indicates that it has been considered
Generally speaking, we adopt grid by grid recursion (in a few cases, we will consider row by row recursion)
Representation of status
Minimum representation
The obstacle is 0, the number in the first connected block is 1, and the number in the second connected block is 2
(another method is to mark each connected block with the leftmost column number)
Bracket notation
There are four plugs a, b, C and D on the contour line from left to right. If a and C are connected and not connected with b, b and D must not be connected. (applicable to all chessboard problems, see CDQ paper for details)
It is not difficult to think of bracket matching. 0 represents no bracket, 1 represents left bracket, and 2 represents right bracket (in the implementation, hexadecimal is generally used, and bit operation is really fragrant)
Some trival details
It is generally considered to scroll dp with map or hash, otherwise the memory will explode
Approximate mode
That is, the classification is crazy and tired. There are only six cases in a grid: up and down, left and right, up left, up right, down left and down right, so the discussion is over and the code of the template is pasted
#include<bits/stdc++.h> using namespace std; namespace DEBUG { void debug_out() { cerr << '\n'; } template <typename Head, typename... Tail> void debug_out(Head H, Tail... T) { cerr << ' ' << H, debug_out(T...); } #define debug(...) cerr << '[' << #__VA_ARGS__ << "]:", debug_out(__VA_ARGS__) } using namespace DEBUG; typedef long long ll; typedef unsigned long long ull; //#define getchar() (S==T&&(T=(S=B)+fread(B,1,1<<15,stdin),S==T)?EOF:*S++) namespace get_out { char B[1<<15],*S=B,*T=B; char op; inline void read_(int &x) { x=0; int fi(1); op=getchar(); while((op<'0'||op>'9')&&op!='-') op=getchar(); if(op=='-') op=getchar(),fi=-1; while(op>='0'&&op<='9') x=(x<<1)+(x<<3)+(op^48),op=getchar(); x*=fi; return; } inline void read_(long long &x) { x=0; int fi(1); op=getchar(); while((op<'0'||op>'9')&&op!='-') op=getchar(); if(op=='-') op=getchar(),fi=-1; while(op>='0'&&op<='9') x=(x<<1)+(x<<3)+(op^48),op=getchar(); x*=fi; return; } inline void read_(double &x) { x=0.0; float fi(1.0),sm(0.0); op=getchar(); while((op<'0'||op>'9')&&op!='-') op=getchar(); if(op=='-') op=getchar(),fi=-1.0; while(op>='0'&&op<='9') x=(x*10.0)+(op^48),op=getchar(); if(op=='.') op=getchar(); int rtim=0; while(op>='0'&&op<='9') sm=(sm*10.0)+(op^48),++rtim,op=getchar(); while(rtim--) sm/=10.0; x+=sm,x*=fi; return; } inline void postive_write(int x) { if(x>9) postive_write(x/10); putchar(x%10|'0'); } inline void postive_write(long long x) { if(x>9) postive_write(x/10); putchar(x%10|'0'); } inline void write_(int x) { if(x<0) x=-x,putchar('-'); postive_write(x); } inline void write_(int x,char ch) { write_(x),putchar(ch); } inline void write_(long long x) { if(x<0) x=-x,putchar('-'); postive_write(x); } inline void write_(long long x,char ch) { write_(x),putchar(ch); } } using get_out::read_; using get_out::write_; #define maxn 15 #define inf 0x7f7f7f7f #define mod 299993 #define hashMaxNum 300000 int n,m,head[hashMaxNum]; int cnt[2],mp[maxn][maxn],edi,edj,now,la; ll ans=0; class hahaha { public: int s[20]; hahaha()=default; hahaha(int state) { s[0]=state&3; for(int i=1;i<=m;++i) s[i]=(state>>(i<<1))&3; } inline int rar() { int state=0; for(int i=1;i<=m;++i) state|=s[i]<<(i<<1); return (state|s[0]); } }; inline hahaha unpack(int state) {return hahaha(state);} inline int rar(hahaha &H){return H.rar();} class hash_T { public: int state[2],nex; ll num[2]; hash_T()=default; }s[hashMaxNum]; inline void insert(int state,ll num) { int tmp=state%mod; for(int i=head[tmp];i;i=s[i].nex) if(state==s[i].state[now]) { s[i].num[now]+=num; return; } s[++cnt[now]].state[now]=state, s[cnt[now]].nex=head[tmp], s[head[tmp]=cnt[now]].num[now]=num; } hahaha now_state,_k; ll lnum; inline void zip_insert() { insert(rar(_k),lnum),_k=now_state; } inline void solve() { register int i,j,k; int west,north; insert(0,1); for(i=1;i<=n;++i) for(j=1;j<=m;++j) { la=now,now^=1;//renew state cnt[now]=0,memset(head,0,sizeof(head));//init for(k=1;k<=cnt[la];++k) { now_state=unpack(s[k].state[la]),_k=now_state; lnum=s[k].num[la],west=now_state.s[0],north=now_state.s[j]; if(!mp[i][j]) {if(!west&&!north) insert(rar(_k),lnum);continue;} if(!west&&!north) { if(mp[i][j+1]&&mp[i+1][j]) _k.s[0]=2, _k.s[j]=1,//Hang up zip_insert(); continue; } if(!west&&north) { if(mp[i+1][j]) insert(rar(_k),lnum); if(mp[i][j+1]) _k.s[0]=north, _k.s[j]=0, zip_insert(); continue; } if(west&&!north) { if(mp[i][j+1]) insert(rar(_k),lnum); if(mp[i+1][j]) _k.s[0]=0, _k.s[j]=west, zip_insert(); continue; } if(west==1&&north==2) { _k.s[0]=_k.s[j]=0; bool flag=0; for(int pos=0;pos<=m;++pos) if(_k.s[pos]) { flag=1; break; } if(!flag&&i==edi&&j==edj) ans+=lnum; continue; } if(west==2&&north==1) { _k.s[0]=_k.s[j]=0; zip_insert(); continue; } if(west==1&&north==1) { int nm=1,pos=j+1; for(;pos<=m;++pos) { nm+=_k.s[pos]==1?1:(_k.s[pos]==2?-1:0); if(!nm) break; } _k.s[pos]=1; _k.s[0]=_k.s[j]=0; zip_insert(); continue; } if(west==2&&north==2) { int nm=-1,pos=j-1; for(;pos;--pos) { nm+=_k.s[pos]==1?1:(_k.s[pos]==2?-1:0); if(!nm) break; } _k.s[pos]=2; _k.s[0]=_k.s[j]=0; zip_insert(); continue; } } } } signed main() { register char ch[20]; read_(n),read_(m); for(int i=1;i<=n;++i) { scanf("%s",ch+1); for(int j=1;j<=m;++j) ((ch[j]=='.'&&(mp[i][j]=1,edi=i,edj=j))||(mp[i][j]=0)); } solve(); cout<<ans<<'\n'; return 0; }