既然是对称走,那么先把对称的格子相加,转换成一个左上三角的样子,要统计所有合法路径中,数字之和最小的路径有多少条?,而我们在统计时的每一次转移都需要走一个最短的路才能保证最终走到副对角线时可能是所有到达对角线上中最短的路,所以事先用bfs求出(0,0)到每个格子的最短路,然后记忆化搜索条数。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#include <map>
#include <cmath>
#include <set>
#include <queue>
using namespace std;
const double INF=1e9+10;
const double EPS = 1e-10;
typedef long long ll;
const int mod=1000000009;
int n,a[205][205],maxn;
int dis[205][205],d[205][205];
const int dx[]={1,-1,0,0},dy[]={0,0,-1,1};
void bfs(){
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
dis[i][j]=INF;
queue<pair<int,int> >que;
que.push(make_pair(0,0));
dis[0][0]=a[0][0];
while(!que.empty()){
pair<int,int> v=que.front();que.pop();
for(int i=0;i<4;i++){
int xx=v.first+dx[i],yy=v.second+dy[i];
if(xx+yy>n-1||xx<0||xx>=n||yy<0||yy>=n) continue;
if(dis[xx][yy]>dis[v.first][v.second]+a[xx][yy]){
dis[xx][yy]=dis[v.first][v.second]+a[xx][yy];
que.push(make_pair(xx,yy));
}
}
}
}
int dfs(int x,int y){
if(d[x][y]!=-1) return d[x][y];
if(x+y==n-1){
if(dis[x][y]==maxn) return 1;
else return 0;
}
ll ans=0;
for(int i=0;i<4;i++){
int xx=x+dx[i],yy=y+dy[i];
if(xx+yy>n-1||xx<0||xx>=n||yy<0||yy>=n) continue;
if(dis[xx][yy]==dis[x][y]+a[xx][yy])
ans=(1LL*ans+dfs(xx,yy))%mod;
}
return d[x][y]=ans;
}
int main(){
//freopen("out.txt","w",stdout);
while(scanf("%d",&n)&&n){
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
scanf("%d",&a[i][j]);
for(int i=0;i<n-1;i++){
for(int j=0;j<n-i-1;j++){
a[i][j]+=a[n-1-j][n-1-i];
}
}
bfs();
maxn=INF;
for(int i=0;i<n;i++) maxn=min(maxn,dis[i][n-i-1]);
memset(d,-1,sizeof(d));
printf("%d\n",dfs(0,0) );
}
return 0;
}