Description
给一个n行n列的网格,每个格子里有一个1到9的数字。你需要从左上角走到右下角,其中每一步只能往上、下、左、右四个方向之一走到相邻格子,不能斜着走,也不能走出网格,但可以重复经过一个格子。为了美观,你经过的路径还必须关于“左下-右上”这条对角线对称。下图是一个6x6网格上的对称路径。
你的任务是统计所有合法路径中,数字之和最小的路径有多少条。
Input
输入最多包含25组测试数据。每组数据第一行为一个整数n(2<=n<=100)。以下n行每行包含n个1到9的数字,表示输入网格。输入结束标志为n=0。
Output
对于每组数据,输出合法路径中,数字之和最小的路径条数除以1,000,000,009的余数。
Sample Input
2 1 1 1 1 3 1 1 1 1 1 1 2 1 1 0
Sample Output
2 3
Hint
无
思路:先把图压缩成左上角的一半 在用dij求出(0,0)点到左下-右上的斜边的各个点的最短路,然后只要斜边上的点满足最短路,就dfs深搜路径到(0.0)点,并用一个vis1标记当前坐标是否搜索过,如果搜索过直接返回该值,就是记忆化搜索,并且搜索的条件是当前的点加上当前点的权值要等于刚才走过来那个点的最短路的值才往下搜,因为要保证最短路,
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <queue>
#include <algorithm>
typedef __int64 LL;
using namespace std;
LL mod = 1000000009;
const int maxn = 222222222;
int vis[210][210],head[210][210],n,cnt,d[210][210],map[210][210];
struct Edge
{
int u[2],v[2],w;
int next;
Edge(int a =0,int b = 0,int e= 0,int r = 0,int c = 0)
{
u[0] = a; u[1] = b; w = c;v[0] = e;v[1] = r;
}
}e[450000];
void add(Edge q)
{
e[cnt].u[0] = q.u[0];
e[cnt].u[1] = q.u[1];
e[cnt].v[0] = q.v[0];
e[cnt].v[1] = q.v[1];
e[cnt].w = q.w;
e[cnt].next = head[q.u[0]][q.u[1]];
head[q.u[0]][q.u[1]] = cnt++;
}
struct node
{
int x, y, val;
friend bool operator <(node a, node b)
{
return a.val > b.val;
}
node (int a=0, int b=0, int c=0)
{
x = a; y = b;val = c;
}
};
void dij()
{
memset(vis,0,sizeof(vis));
int i,j;
for(i = 0; i<n;i++)
{
for(j = 0; j<n;j++)
{
d[i][j] = maxn;
}
}
d[0][0] = map[0][0];
priority_queue <node> q;
q.push(node (0,0,d[0][0]));
while (!q.empty())
{
node w = q.top();
q.pop();
if(vis[w.x][w.y] == 1)
{
continue;
}
vis[w.x][w.y] = 1;
for(i = head[w.x][w.y];i!=-1;i=e[i].next)
{
int end1 = e[i].v[0];
int end2 = e[i].v[1];
if(d[end1][end2] > d[w.x][w.y] + e[i].w)
{
d[end1][end2] = d[w.x][w.y] + e[i].w;
q.push(node (end1,end2,d[end1][end2]));
}
}
}
}
int ans1,aa[4] = {1,-1,0,0},bb[4]={0,0,1,-1},vis1[210][210];
LL ans,dp[210][210];
LL dfs(int x, int y)
{
if(x == 0&&y ==0)
return 1;
if(vis1[x][y] == 1)
return dp[x][y];
vis1[x][y] = 1;
int i;
dp[x][y] = 0;
for(i = 0; i < 4; i++)
{
int x1 = x + aa[i];
int y1 = y + bb[i];
if(x1>=0&&x1<n&&y1>=0&&y1<n-x1&&(d[x1][y1]+map[x][y] == d[x][y]))
{
dp[x][y] =( dp[x][y]%mod + dfs(x1,y1)%mod)%mod;
}
}
return dp[x][y];
}
int main()
{
int i,j,k;
while (scanf("%d",&n)&&n)
{
for(i = 0; i<n;i++)
{
for(j = 0; j < n; j++)
{
scanf("%d",&map[i][j]);
}
}
for(i = 0; i<n;i++)
{
for(j = 0; j < n - i; j++)
{
if(j!=n-i-1)
map[i][j] += map[n-j-1][n-i-1];
}
}
memset(head,-1,sizeof(head));
cnt = 0;
for(i = 0; i<n;i++)
{
for(j = 0; j < n-i; j++)
{
for(k = 0; k < 4; k++)
{
if(i+aa[k]>=0&&i+aa[k]<n&&j+bb[k]>=0&&j+bb[k]<n-i-aa[k])
{
add(Edge(i,j,i+aa[k],j+bb[k],map[i+aa[k]][j+bb[k]]));
}
}
}
}
dij();
ans1 = maxn;
ans = 0;
for(i = 0; i<n;i++)
{
if(d[i][n-i-1] < ans1)
ans1 = d[i][n-i-1];
}
memset(vis1,0,sizeof(vis1));
dp[0][0] = 1;
for(i = 0; i < n; i++)
{
if(d[i][n-1-i] == ans1)
ans=(ans%mod+dfs(i,n-1-i)%mod)%mod;
}
cout<<ans<<endl;
}
return 0;
}