【题目描述】
给你一个 n*m 的地图,有的格子存在障碍,求 从左下角走到右下角 且经过所有非障碍格子一次(仅一次)的路径总数。
题解:
巧妙啊!考虑到起点和终点的特殊性,我们可以把这题转化为一个回路问题,那么又跟caioj1489一样了:在最后新增两行,第
n+1
行的第
1
列和第
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define LL long long
const int mod=100037;
int n,m,map[15][15],xx,yy,now,list[2][mod],num[2];
// 状态列表 状态总数
LL state[2][mod],ans;
int HASH[mod];
LL get(int s,int p)//获取状态s从右向左数的第p位
{return (s>>((p-1)*2))&3;}
void change(int &s,int p,int v)//把状态s的第p位改成v
{
s^=get(s,p)<<((p-1)*2);
s^=(v)<<((p-1)*2);
}
void add(int now,int st,LL sum)
{
int ss=st%mod;
while(list[now][HASH[ss]]!=st&&HASH[ss]!=-1)
{
ss++;ss%=mod;
if(ss==0)ss=1;
}
if(HASH[ss]==-1)
{
HASH[ss]=++num[now];
list[now][num[now]]=st;
state[now][num[now]]=sum;
}
else state[now][HASH[ss]]+=sum;
}
void work()
{
state[0][1]=1;num[0]=1;list[0][1]=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
now^=1;
num[now]=0;
memset(HASH,-1,sizeof(HASH));
for(int k=1;k<=num[now^1];k++)
{
int st=list[now^1][k];//获取上次的状态
LL sum=state[now^1][k];//获取此状态的数目
int p=get(st,j);//获取上次的两个插头
int q=get(st,j+1);
if(!map[i][j])//障碍点
{
if(!p&&!q)add(now,st,sum);
continue;
}
if(!p&&!q)//没有连到当前的格子
{
if(map[i][j+1]&&map[i+1][j])
{
change(st,j,1);
change(st,j+1,2);
add(now,st,sum);
}
}
else if(!p&&q)
{
if(map[i][j+1])add(now,st,sum);
if(map[i+1][j])
{
change(st,j,q);
change(st,j+1,0);
add(now,st,sum);
}
}
else if(p&&!q)
{
if(map[i+1][j])add(now,st,sum);
if(map[i][j+1])
{
change(st,j,0);
change(st,j+1,p);
add(now,st,sum);
}
}
else if(p==1&&q==2)
{
if(i==xx&&j==yy)ans+=sum;
}
else if(p==2&&q==1)
{
change(st,j,0);
change(st,j+1,0);
add(now,st,sum);
}
else if(p==1&&q==1)
{
int top=1;
for(int pos=j+2;pos<=m+1;pos++)
{
int temp=get(st,pos);
if(temp==1)top++;
if(temp==2)top--;
if(top==0)
{
change(st,j,0);
change(st,j+1,0);
change(st,pos,1);
add(now,st,sum);
break;
}
}
}
else if(p==2&&q==2)
{
int top=1;
for(int pos=j-1;pos;pos--)
{
int temp=get(st,pos);
if(temp==2)top++;
if(temp==1)top--;
if(top==0)
{
change(st,j,0);
change(st,j+1,0);
change(st,pos,2);
add(now,st,sum);
break;
}
}
}
}
}
for(int j=1;j<=num[now];j++)list[now][j]<<=2;
}
}
int main()
{
while(1)
{
scanf("%d%d",&n,&m);
if(!n&&!m)break;
memset(map,0,sizeof(map));
now=ans=0;
for(int i=1;i<=n;i++)
{
char str[15];
scanf("%s",str);
for(int j=1;j<=m;j++)
if(str[j-1]=='.')map[i][j]=1;
}
map[n+1][1]=map[n+1][m]=1;
for(int j=2;j<m;j++)map[n+1][j]=0;
for(int j=1;j<=m;j++)
map[n+2][j]=1;
n+=2;xx=n;yy=m;
work();
printf("%lld\n",ans);
}
}