题意:求一些格子不能经过,可以经过的格子要经过的回路个数。。
插头DP入门题。。
用括号表示法写的。。。为了方便用了4进制。。0代表没有插头,1代表是(,2代表是)
总体就是分几种情况转移。。。
在格子可以经过的条件下。。
转移就是 ##->() 左插头和上插头都没有
左插头和右插头只存在一个 (#->(# (#->#( )#->)# )#->#) ,右插头存在同理。。
然后就是两个插头都存在了,如果是()。。就是结束了,刚好匹配了。。
是)(,左边的和左边的匹配,右边的和右边的匹配,)(->##
((->##,然后把右边的一个(变成)。。
))同理。。
http://blog.sina.com.cn/s/blog_51cea4040100gmky.html这里更加详细
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int MAXN=100010;
struct HASHMAP
{
int head[MAXN],size;
int S[MAXN];
ll sum[MAXN];
void init()
{
memset(head,-1,sizeof(head));
size=0;
}
void push(int SS,ll num)
{
int s=SS%MAXN;
while(head[s]!=-1&&S[head[s]]!=SS)
s=(s+1)%MAXN;
if(head[s]!=-1)
sum[head[s]]+=num;
else
{
sum[size]=num;
S[size]=SS;
head[s]=size++;
}
}
ll get(int SS)
{
int s=SS%MAXN;
while(head[s]!=-1&&S[head[s]]!=SS)
s=(s+1)%MAXN;
if(head[s]!=-1)
return sum[head[s]];
else
return 0;
}
}dp[2];
int now,pre;
int get(int S,int p,int l=2)
{
return (S>>(p*l))&((1<<l)-1);
}
void set(int &S,int p,int v,int l=2)
{
S^=get(S,p,l)<<(p*l);
S^=(v&((1<<l)-1))<<(p*l);
}
char mat[20][20];
int mp[20][20];
int n,m,endx,endy;
void input()
{
int i,j;
endx=-1;
memset(mp,0,sizeof(mp));
for(i=0;i<n;i++)
{
scanf("%s",mat[i]);
for(j=0;j<m;j++)
{
if(mat[i][j]=='*')
{
mp[i][j]=0;
}
else if(mat[i][j]=='.')
{
mp[i][j]=1;
endx=i;
endy=j;
}
}
}
}
ll slove()
{
ll ans=0;
int i,j,k;
now=1,pre=0;
dp[now].init();
dp[now].push(0,1);
for(i=0;i<n;i++)
{
for(j=0;j<m;j++)
{
swap(now,pre);
dp[now].init();
for(k=0;k<dp[pre].size;k++)
{
int S=dp[pre].S[k];
ll num=dp[pre].sum[k];
int p=get(S,j);
int q=get(S,j+1);
if(mp[i][j]==0)
{
if(p==0&&q==0)
dp[now].push(S,num);
continue;
}
if(p==0&&q==0)
{
if(mp[i+1][j]&&mp[i][j+1])
{
set(S,j,1);
set(S,j+1,2);
dp[now].push(S,num);
}
}
else if( (p>0)^(q>0) )
{
if(mp[i+(p>0)][j+(q>0)])
{
dp[now].push(S,num);
}
if(mp[i+(q>0)][j+(p>0)])
{
set(S,j,q);
set(S,j+1,p);
dp[now].push(S,num);
}
}
else if(p==2&&q==1)
{
set(S,j,0);
set(S,j+1,0);
dp[now].push(S,num);
}
else if(p==1&&q==1)
{
int x=1;
for(int kk=j+2;kk<=m;kk++)
{
int v=get(S,kk);
if(v==1)
x++;
else if(v==2)
x--;
if(x==0)
{
set(S,j,0);
set(S,j+1,0);
set(S,kk,1);
dp[now].push(S,num);
break;
}
}
}
else if(p==2&&q==2)
{
int x=1;
for(int kk=j-1;kk>=0;kk--)
{
int v=get(S,kk);
if(v==1)
x--;
else if(v==2)
x++;
if(x==0)
{
set(S,j,0);
set(S,j+1,0);
set(S,kk,2);
dp[now].push(S,num);
break;
}
}
}
else if(p==1&&q==2)
{
if(i==endx&&j==endy)
ans+=num;
}
}
}
for(int kk=0;kk<dp[now].size;kk++)
{
dp[now].S[kk]<<=2;
}
}
return ans;
}
int main()
{
while(scanf("%d%d",&n,&m)==2)
{
input();
if(endx==-1)
{
printf("0\n");
continue;
}
printf("%I64d\n",slove());
}
return 0;
}