我们把对角线下面的权值放到上面,然后将对角线上任意一点作为终点。
然后最短路计数一下就好了。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const ll N=2e2+5;
const ll Inf=1e18;
const ll Mod=1e9+9;
ll n,t,mp[N][N],id[N][N];
ll dis[N*N],vis[N*N],tot[N*N];
ll cnt,to[N*N],edge[N*N],nxt[N*N],head[N*N];
ll dx[4]={0,0,-1,1};
ll dy[4]={1,-1,0,0};
struct node {
ll num,dis;
bool operator < (const node &a) const {
return a.dis<dis;
}
};
inline ll add(ll x,ll y) {
return x+y>=Mod?x+y-Mod:x+y;
}
bool check(ll x,ll y) {
return 1<=x&&x<=n&&1<=y&&y<=n;
}
void ins(ll x,ll y,ll z) {
to[++cnt]=y;edge[cnt]=z;nxt[cnt]=head[x];head[x]=cnt;
}
void dij(ll s) {
priority_queue<node>pq;
for(ll i=1;i<=n*n;i++) dis[i]=Inf,vis[i]=tot[i]=0;
dis[s]=0;tot[s]=1;node tmp;tmp.num=s;pq.push(tmp);
while(pq.size()) {
ll x=pq.top().num;pq.pop();
if(!vis[x]) {
vis[x]=1;
for(ll i=head[x];i;i=nxt[i]) {
ll y=to[i],z=edge[i];
if(dis[y]>dis[x]+z) {
dis[y]=dis[x]+z;tot[y]=tot[x];
tmp.num=y;tmp.dis=dis[y];pq.push(tmp);
} else if (dis[y]==dis[x]+z) tot[y]=add(tot[y],tot[x]);
}
}
}
}
int main() {
while(~scanf("%lld",&n)) {
if(n==0) return 0;
cnt=t=0;memset(head,0,sizeof(head));
for(ll i=1;i<=n;i++) for(ll j=1;j<=n;j++) scanf("%lld",&mp[i][j]);
for(ll i=1;i<n;i++) for(ll j=1;j<=n-i;j++) mp[i][j]=add(mp[i][j],mp[n+1-j][n+1-i]);
for(ll i=1;i<=n;i++) for(ll j=1;j<=n;j++) id[i][j]=++t;
for(ll i=1;i<n;i++) for(ll j=1;j<=n-i;j++) {
for(ll k=0;k<=3;k++) if(check(i+dx[k],j+dy[k])) {
ins(id[i][j],id[i+dx[k]][j+dy[k]],mp[i+dx[k]][j+dy[k]]);
}
}
dij(1);
ll ans=Inf,num=0;
for(ll i=1;i<=n;i++) {
if(dis[id[i][n+1-i]]<ans) {
ans=dis[id[i][n+1-i]];num=tot[id[i][n+1-i]];
} else if (dis[id[i][n+1-i]]==ans) num+=tot[id[i][n+1-i]];
}
printf("%lld\n",num);
}
}