今天在TYB大佬的带领下学了一发新姿势啊!!
感觉几年前的省选考过插头DP,就有一点点想学了。。
但是好像以前研究过一小阵子。。
由于没看懂就放弃了。。
然后这次跟着TYB大佬又来了一发。。
感觉还好
感觉这个算法的核心思想就是不断地分类讨论。。
要注意的地方很多。。
然后想学的人还是先看看论文,弄清楚点概念什么的
至于分类讨论,看代码就好
下面是我的代码,有“详细”的注释
哦,还有,学这个东西的时候一定要有纸和笔。。没看懂的地方一定要画。。不要相信什么人脑是无敌的
#include<cstdio>
#include<cstring>
#define ADD add(st,sum)
typedef long long LL;
const int MOD=100037;
const int N=15;
bool map[N][N];//是不是可以走
int n,m;
int xx=-1,yy;//我们要寻找一个最下 最右的点——>当到他的时候就可以累计答案了
LL ans=0;//答案个数
LL a[2][MOD];//这种状态的数目,其实差不多是来辅助下面的数组
int b[2][MOD];//状态
int num[2];//状态个数
int HASH[MOD];
/*0:无插头状态
1:左括号插头
2:右括号插头*/
int get (int x,int p)//第j位 当然是四进制里面的第j位啦
{return (x>>(p-1)*2)&3;}
int now=0;
void add (int st,LL sum)//给当前的决策状态加上这个状态
{
int ss=st%MOD;
while (HASH[ss]!=-1&&b[now][HASH[ss]]!=st)
{
ss++;ss%=MOD;
if (ss==0) ss=1;
}
if (HASH[ss]==-1)
{
HASH[ss]=++num[now];
b[now][num[now]]=st;
a[now][num[now]]=sum;
}
else a[now][HASH[ss]]+=sum;
}
void change (int &s,int p,int v)//把s的第p位改为v
{
s=s^(get(s,p)<<(p-1)*2);
s=s^(v<<(p-1)*2);
}
void solve ()
{
a[0][1]=1;num[0]=1;b[0][1]=0;
for (int u=1;u<=n;u++)
{
for (int i=1;i<=m;i++)//当前的转移节点,我们要尝试吧这个节点转到下一个
{
now^=1;
num[now]=0;
memset(HASH,-1,sizeof(HASH));
for (int k=1;k<=num[now^1];k++)//继承上一个轮廓线的状态
{
int st=b[now^1][k];
LL sum=a[now^1][k];
int p=get(st,i);//获得“竖着的”那个插头状态
int q=get(st,i+1);//获得“横着的”那个插头状态
// printf("%d %d %d %d %d %d\n",u,i,k,st,p,q);
if (map[u][i]==false)//这个是障碍点
{
if (p+q==0) ADD;//要是可以把它绕开就好了
continue;
}
if (p+q==0)//没有连到当前格子
{
if (map[u][i+1]&&map[u+1][i])
{
change(st,i,1);
change(st,i+1,2);
ADD;
}
}
else if (p==0&&q!=0)
{
if (map[u][i+1]==true) ADD;
if (map[u+1][i]==true)
{
change(st,i,q);
change(st,i+1,0);
ADD;
}
}
else if (p!=0&&q==0)
{
if (map[u+1][i]==true) ADD;
if (map[u][i+1]==true)
{
change(st,i,0);
change(st,i+1,p);
ADD;
}
}
else if (p==1&&q==2)
{
if (u==xx&&i==yy)
ans+=sum;
}
else if (p==2&&q==1)
{
change(st,i,0);
change(st,i+1,0);
ADD;
}
else if (p==1&&q==1)
{
int top=1;
for (int pos=i+2;pos<=m+1;pos++)
{
int temp=get(st,pos);
if (temp==1) top++;
if (temp==2) top--;
if (top==0)
{
change(st,i,0);
change(st,i+1,0);
change(st,pos,1);
ADD;
break;
}
}
}
else if (p==2&&q==2)
{
int top=1;
for (int pos=i-1;pos>0;pos--)
{
int temp=get(st,pos);
if (temp==2) top++;
if (temp==1) top--;
if (top==0)
{
change(st,i,0);
change(st,i+1,0);
change(st,pos,2);
ADD;
break;
}
}
}
}
}
for (int i=1;i<=num[now];i++) b[now][i]<<=2;
}
}
int main()
{
memset(map,false,sizeof(map));
scanf("%d%d",&n,&m);
for (int u=1;u<=n;u++)
{
char ss[15];
scanf("%s",ss+1);
for (int i=1;i<=m;i++)
if (ss[i]=='.')
{xx=u;yy=i;map[u][i]=true;}
}
if (xx==-1) {printf("0");return 0;}
solve();
printf("%lld\n",ans);
return 0;
}