版权声明:本篇随笔版权归作者Etta(http://www.cnblogs.com/Etta/)所有,转载请保留原地址!
问题描述:
小鼠a与小鼠b身处一个m×n的迷宫中,如图所示。每一个方格表示迷宫中的一个房间。这m×n个房间中有一些房间是封闭的,不允许任何人进入。在迷宫中任何位置均可沿上,下,左,右4个方向进入未封闭的房间。小鼠a位于迷宫的(p,q)方格中,它必须找出一条通向小鼠b所在的(r,s)方格的路。请帮助小鼠a找出所有通向小鼠b的最短道路。
编程任务:
对于给定的小鼠的迷宫,编程计算小鼠a通向小鼠b的所有最短道路。
数据输入:
由文件input.txt给出输入数据。第一行有3个正整数n,m,k,分别表示迷宫的行数,列数和封闭的房间数。接下来的k行中,每行2个正整数,表示被封闭的房间所在的行号和列号。最后的2行,每行也有2个正整数,分别表示小鼠a所处的方格(p,q)和小鼠b所处的方格(r,s)。
结果输出:
将计算出的小鼠a通向小鼠b的最短路长度和有多少条不同的最短路输出到文件output.txt。文件的第一行是最短路长度。文件的第2行是不同的最短路数。
如果小鼠a无法通向小鼠b则输出“No Solution!”。
Input:
8 8 3
3 3
4 5
6 6
2 1
7 7
Output:
11
96
一、分析问题
看到这道题想起搜索里经典的走迷宫求路径,于是直接bfs求最短路dfs搜路径数,奈何一个点始终TLE。于是有另一个快且简洁的方法。把每一个格子抽象为一个点,相邻的点之间有长度为1的边,SPFA求最短路径,递推求最短路径数。
二、解决问题
SPFA+递推
Tips:
1.递推是难点
if(dis[u]>dis[v]+1)f[u]=f[v];
else if(dis[u]==dis[v]+1)f[u]+=f[v];//
2.使用一维数组代替二维数组使得队列实现更加方便
F[i,j]=>f[i*(m-1)+j]
3.m*n的表格,m行n列//
三、代码实现
1 #include<cstdio> 2 #include<queue> 3 using namespace std; 4 5 const int MA=100,inf=4e8; 6 int m,n,k,st,en; 7 int x,y,t,a,b,c,d; 8 int dis[MA*MA],fa[MA*MA],ex[MA*MA]; 9 queue<int>p; 10 11 int calc(int x,int y) 12 { 13 return (x-1)*m+y; 14 } 15 16 void spfa(int u,int v) 17 { 18 if(dis[u]>dis[v]+1) 19 { 20 fa[u]=fa[v]; 21 dis[u]=dis[v]+1; 22 if(!ex[u]) 23 { 24 p.push(u); 25 ex[u]=1; 26 } 27 } 28 else 29 if(dis[u]==dis[v]+1) 30 fa[u]+=fa[v]; 31 } 32 33 void SPFA() 34 { 35 p.push(st); 36 dis[st]=0; 37 fa[st]=1; 38 while(!p.empty()) 39 { 40 int tmp=p.front(); 41 ex[tmp]=0; 42 p.pop(); 43 if(tmp+m<=n*m&&dis[tmp+m]!=-1)spfa(tmp+m,tmp); 44 if(tmp-m>=0&&dis[tmp-m]!=-1)spfa(tmp-m,tmp); 45 if(tmp%m!=0&&dis[tmp+1]!=-1)spfa(tmp+1,tmp); 46 if(tmp%m!=1&&dis[tmp-1]!=-1)spfa(tmp-1,tmp); 47 } 48 } 49 50 int main() 51 { 52 scanf("%d%d%d",&n,&m,&k); 53 for(int i=1;i<=n*m;++i)dis[i]=inf; 54 for(int i=1;i<=k;++i) 55 { 56 scanf("%d%d",&x,&y); 57 t=calc(x,y); 58 dis[t]=-1; 59 } 60 scanf("%d%d%d%d",&a,&b,&c,&d); 61 st=calc(a,b); 62 en=calc(c,d); 63 64 SPFA(); 65 66 if(dis[en]==inf)printf("No Solution! "); 67 else printf("%d %d ",dis[en],fa[en]); 68 return 0; 69 }