有一个n*n的矩阵,要求从(1,1)到(n,n)的最短路数量,路径的权值是所经过元素的和,且路径与对角线对称。
由于路径是对称的,可以先预处理将右下角的元素加到左上角,那么就只用计算(1,1)到对角线的最短路数量了,计算最短路可以用dijkstra,要计算数量只需要在dijkstra的过程中递推一下就好了。
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1e2+5;
const int mod=1e9+9;
const int inf=0x3f3f3f3f;
int zu[maxn][maxn],n;
int dis[maxn][maxn],num[maxn][maxn];
bool mark[maxn][maxn];
int dir[4][2]={0,1,0,-1,1,0,-1,0};
void dijkstra()
{
memset(mark,false,sizeof(mark));
memset(dis,inf,sizeof(dis));
memset(num,0,sizeof(num));
dis[1][1]=zu[1][1],num[1][1]=1;
int lim=(n*n-n)/2,cnt=0;
while(cnt++<lim)
{
int r,c,d=inf;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n-i;j++)
{
if(!mark[i][j]&&dis[i][j]<d)
{
d=dis[i][j];
r=i,c=j;
}
}
}
mark[r][c]=true;
for(int i=0;i<4;i++)
{
int rr=r+dir[i][0],cc=c+dir[i][1];
if(rr<1||rr>n||cc<1||cc>n) continue;
if(dis[rr][cc]>dis[r][c]+zu[rr][cc])
{
dis[rr][cc]=dis[r][c]+zu[rr][cc];
num[rr][cc]=num[r][c]%mod;
}
else if(dis[rr][cc]==dis[r][c]+zu[rr][cc])
num[rr][cc]=(num[rr][cc]+num[r][c])%mod;
}
}
}
int main()
{
while(scanf("%d",&n)!=-1)
{
if(n==0) break;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%d",&zu[i][j]);
for(int i=1;i<=n;i++)
for(int j=1;j<=n-i;j++)
zu[i][j]+=zu[n-j+1][n-i+1];
dijkstra();
int mindis=inf;
for(int i=1;i<=n;i++)
mindis=min(mindis,dis[i][n-i+1]);
int ans=0;
for(int i=1;i<=n;i++)
{
if(dis[i][n-i+1]==mindis)
ans=(ans+num[i][n-i+1])%mod;
}
printf("%d\n",ans);
}
return 0;
}