这道题与最短路有关应该是比较容易看出的,然后如果没有第二问,我们怎么建图都可以,比如说将莲花与莲花之间建一条边权为0的边,莲花与水建一条边权为1的边,水与水之间建一条边权为1的边,然后跑最短路。这样虽然能够解决第一问,但第二问却无从下手,我们可以感觉到第二问的方案数应该与最短路的方案数有关,但是如果按照上述建图的话,我们很难发现什么关系,因为如果经过的水面相同而经过的莲花不同,会被算作是不同的最短路,而实际上方案却是一样的,我们考虑不同的最短路指的是这条路径上经过的点不完全相同,那如果我们能在跑最短路时只经过水面,这样的最短路方案数一定是题目中要求的方案数,那我们怎么办呢,我们考虑其实莲花与莲花之间的边是没有意义的,它不过是为了保证连通性,同理,除起点和终点外的莲花与水之间的边也是没有意义的,那么我们考虑换一种建图方式,对于每个水,我们将从它能直接跳到或经过若干莲花后能跳到的水连边,将起点和终点与水连边,这样跑最短路,我们发现经过这样建图后最短路上的点除起点和终点是莲花之外,其余的点全是水,这样不同的最短路就对应着经过了不同的水,也就对应着不同的放莲花的方案。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 130005
int n,m,g[35][35],sx,tx,sy,ty,l,cnt;
int pre[maxn],last[maxn],other[maxn];
int quex[1000000],quey[1000000],que[1000000];
const int dx[9]={0,1,1,2,2,-1,-1,-2,-2};
const int dy[9]={0,-2,2,-1,1,-2,2,-1,1};
int flag[35][35],dis[1005];
bool vis[1005][1005],vist[maxn];
long long f[1005];
void connect(int x,int y)
{
l++;
pre[l]=last[x];
last[x]=l;
other[l]=y;
}
void bfs(int fx,int fy)
{
flag[fx][fy]=++cnt;
int h=1,t=0;
for (int i=1;i<=8;i++)
{
int xx=fx+dx[i];
int yy=fy+dy[i];
if (xx<1||xx>n||yy<1||yy>m) continue;
if (flag[xx][yy]==cnt) continue;
flag[xx][yy]=cnt;
if (g[xx][yy]!=2&&g[xx][yy]!=0)
{
t++;
quex[t]=xx;quey[t]=yy;
int id1=(fx-1)*m+fy;
int id2=(xx-1)*m+yy;
if (vis[id1][id2]) continue;
connect(id1,id2);
connect(id2,id1);
vis[id1][id2]=vis[id2][id1]=1;
}
else if (g[xx][yy]==0)
{
int id1=(fx-1)*m+fy;
int id2=(xx-1)*m+yy;
if (vis[id1][id2]) continue;
connect(id1,id2);
connect(id2,id1);
vis[id1][id2]=vis[id2][id1]=1;
}
}
while (h<=t)
{
int x=quex[h],y=quey[h];h++;
for (int i=1;i<=8;i++)
{
int xx=x+dx[i];
int yy=y+dy[i];
if (xx<1||xx>n||yy<1||yy>m) continue;
if (flag[xx][yy]==cnt) continue;
flag[xx][yy]=cnt;
if (g[xx][yy]==0)
{
int id1=(fx-1)*m+fy;
int id2=(xx-1)*m+yy;
if (vis[id1][id2]) continue;
connect(id1,id2);
connect(id2,id1);
vis[id1][id2]=vis[id2][id1]=1;
}
else if (g[xx][yy]!=2&&g[xx][yy]!=0)
{
t++;
quex[t]=xx;quey[t]=yy;
}
}
}
}
void spfa(void)
{
memset(dis,53,sizeof dis);
dis[(sx-1)*m+sy]=0;
que[1]=(sx-1)*m+sy;
int h=1,t=1;
while (h<=t)
{
int u=que[h];h++;
vist[u]=0;
for (int p=last[u];p;p=pre[p])
{
int v=other[p];
if (dis[v]>dis[u]+1)
{
dis[v]=dis[u]+1;
if (!vist[v])
{
que[++t]=v;
vist[v]=1;
}
}
}
}
}
void solve(void)
{
memset(vist,0,sizeof vist);
que[1]=(sx-1)*m+sy;f[que[1]]=1;
int h=1,t=1;
while (h<=t)
{
int u=que[h];h++;
for (int p=last[u];p;p=pre[p])
{
int v=other[p];
if (dis[v]==dis[u]+1)
{
f[v]+=f[u];
if (!vist[v])
{
que[++t]=v;
vist[v]=1;
}
}
}
}
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
{
scanf("%d",&g[i][j]);
if (g[i][j]==3) {sx=i;sy=j;}
if (g[i][j]==4) {tx=i;ty=j;}
}
bfs(sx,sy);
bfs(tx,ty);
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
if (g[i][j]==0) bfs(i,j);
spfa();
if (dis[(tx-1)*m+ty]>1e7)
{
printf("-1\n");
return 0;
}
printf("%d\n",dis[(tx-1)*m+ty]-1);
solve();
printf("%lld\n",f[(tx-1)*m+ty]);
return 0;
}