题意:
给出蜂巢形状的地图,有障碍物,求走遍蜂巢的回路个数
题解:
多回路的加强版,这题真心难做,很难想到,按照列dp会更简单点。具体看代码
#include<iostream>
#include<math.h>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<vector>
#include<map>
using namespace std;
typedef long long lld;
#define oo 0x3f3f3f3f
#define OO 0x3f3f3f3f3f3f3f3f
#define HASH 10007
#define STATE 2000010
#define MAXD 32
int N,M;
int code[MAXD],maze[MAXD][MAXD];
struct HASHMAP
{
int head[HASH],next[STATE],state[STATE],sizes;
lld dp[STATE];
void init()
{
sizes=0;
memset(head,-1,sizeof head);
}
void push(int st,lld ans)
{
int h=st%HASH;
for(int i=head[h];i!=-1;i=next[i])
{
if(st==state[i])
{
dp[i]+=ans;
return ;
}
}
dp[sizes]=ans;
state[sizes]=st;
next[sizes]=head[h];
head[h]=sizes++;
}
}hm[2];
void decode(int code[],int m,int st)
{
for(int i=m;i>=0;i--)
{
code[i]=st&1;
st>>=1;
}
}
int encode(int code[],int m)
{
int st=0;
for(int i=0;i<=m;i++)
{
st<<=1;
st|=code[i];
}
return st;
}
void shift(int code[],int m)//换行 移位
{
for(int i=m;i>1;i--)
code[i]=code[i-2];
code[0]=0;
code[1]=0;
}
void dpblank(int i,int j,int cur)
{
int left,up1,up2;
int t1,t2;
if(i%2==0) t1=j,t2=j+1;
else t1=j-1,t2=j;
for(int k=0;k<hm[cur].sizes;k++)
{
decode(code,2*M,hm[cur].state[k]);
left=code[2*(j-1)];
up1=code[2*j-1];
up2=code[2*j];
int cnt=0;
if(left)cnt++;
if(up1)cnt++;
if(up2)cnt++;
///同时有三个插头的轻情况是不存在的,必然会一个点走多次或者环的外面多了插头,这样就不是纯粹的环了
if(cnt==2)///有两个插头插头,这种情况下相当于合并两个连通分量
{
code[2*j-2]=code[2*j-1]=code[2*j]=0;
if(j==M&&i%2==0)shift(code,2*M);
hm[cur^1].push(encode(code,2*M),hm[cur].dp[k]);
}
else if(cnt==1)///只有一个插头,这种情况相当于延续原来的连通分量
{
if(maze[i+1][t1])
{
code[2*j-2]=1;
code[2*j-1]=code[2*j]=0;
if(j==M&&i%2==0)shift(code,2*M);///只要t1才换行,因为t1靠左边,t2靠右边既然t1换了行t2就不用了
hm[cur^1].push(encode(code,2*M),hm[cur].dp[k]);
}
if(maze[i+1][t2])
{
code[2*j-1]=1;
code[2*j-2]=code[2*j]=0;
hm[cur^1].push(encode(code,2*M),hm[cur].dp[k]);
}
if(maze[i][j+1])
{
code[2*j]=1;
code[2*j-2]=code[2*j-1]=0;
hm[cur^1].push(encode(code,2*M),hm[cur].dp[k]);
}
}
else if(cnt==0)///没有插头,相当于构成一个新的连通块
{
if(maze[i+1][t1]&&maze[i+1][t2])
{
code[2*j-2]=code[2*j-1]=1;
code[2*j]=0;
hm[cur^1].push(encode(code,2*M),hm[cur].dp[k]);
}
if(maze[i][j+1]&&maze[i+1][t1])
{
code[2*j-2]=code[2*j]=1;
code[2*j-1]=0;
hm[cur^1].push(encode(code,2*M),hm[cur].dp[k]);
}
if(maze[i][j+1]&&maze[i+1][t2])
{
code[2*j-1]=code[2*j]=1;
code[2*j-2]=0;
hm[cur^1].push(encode(code,2*M),hm[cur].dp[k]);
}
}
}
}
void dpblock(int i,int j,int cur)
{
for(int k=0;k<hm[cur].sizes;k++)
{
decode(code,2*M,hm[cur].state[k]);
code[2*j-2]=code[2*j-1]=code[2*j]=0;///因为有障碍物所以 左插头j-1 和 上插头j 都消失了(就是不联通了)
if(j==M&&i%2==0)shift(code,2*M);
hm[cur^1].push(encode(code,2*M),hm[cur].dp[k]);
}
}
void init()
{
int t=N;
N=8;
char str[10];
memset(maze,0,sizeof maze);
for(int i=1;i<=N;i++)
for(int j=1;j<=M;j++)
maze[i][j]=1;
while(t--)
{
scanf("%s",str);
maze[str[1]-'A'+1][M-(str[0]-'A')]=0;
}
}
void solve()
{
int cur=0;
hm[cur].init();
hm[cur].push(0,1);
for(int i=1;i<=N;i++)
for(int j=1;j<=M;j++)
{
hm[cur^1].init();
if(maze[i][j])dpblank(i,j,cur);
else dpblock(i,j,cur);
cur^=1;
}
lld ans=0;
for(int i=0;i<hm[cur].sizes;i++)
if(hm[cur].state[i]==0)
ans+=hm[cur].dp[i];
printf("%lld\n",ans);
}
int main()
{
while(scanf("%d %d",&M,&N)!=EOF)
{
init();
solve();
}
return 0;
}
/**
3 5
BB CD BF AH CG
*/