描述
You have a grid of n rows and n columns. Each of the unit squares
contains a non-zero digit. You walk from the top-left square to the
bottom-right square. Each step, you can move left, right, up or down
to the adjacent square (you cannot move diagonally), but you cannot
visit a square more than once. There is another interesting rule: your
path must be symmetric about the line connecting the bottom-left
square and top-right square. Below is a symmetric path in a 6 × 6
grid.
Your task is to find out, among all valid paths, how many of them have
the minimal sum of digits?
Input
There will be at most 25 test cases. Each test case begins with an
integer n (2 ≤ n ≤ 100). Each of the next n lines contains n non-zero
digits (i.e. one of 1, 2, 3, … , 9). These n 2 integers are the
digits in the grid. The input is terminated by a test case with n =
0, you should not process it.
Output
For each test case, print the number of optimal symmetric paths,
modulo 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
思路
首先说题意,有一个n*m
的方格,现在要从(1,1)
点走到(n,m)
点,而且走的路线要沿着对角线对称,可以看着上面的图理解一下。问从在走最短路的情况下,从(1,1)
走到(n,m)
一共有多少种走法。
首先我们要满足题意,也就是要对称,我们可以把这个图沿着对角线对这一下,并且把对称格子的权值加起来,这样的话这个问题就变成了求(1,1)
走到对角线上的格子的最短路径的走法。
那么我们从(1,1)
点开始bfs
利用优先队列使权值小的先出队,计算出来从起点走到每一个点的最小权值。
然后遍历一下对角线上的点,当这个点的权值等于要求的最短路的话,就从这个点进行记忆化搜索,令step[x][y]
来记录从(1,1)
点走到(x,y)
点的最小方案数,我们可以知道step[1][1]=1
,最后把方案数累加起来就好了
代码
#include <bits/stdc++.h>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
#define inf 0x3f3f3f3f
typedef long long ll;
const ll N=100+20;
const ll mod=1e9+7;
ll e[N][N],n;
ll go[4][2]= {1,0,-1,0,0,1,0,-1};
ll dp[N][N];
ll step[N][N];
struct node
{
ll x,y,w;
node() {}
node(ll _x,ll _y,ll _w)
{
x=_x;
y=_y;
w=_w;
}
bool friend operator < (node a,node b)
{
return a.w>b.w;
}
};
void bfs()
{
dp[1][1]=e[1][1];
priority_queue<node>q;
q.push(node(1,1,e[1][1]));
while(!q.empty())
{
node now=q.top();
q.pop();
if(dp[now.x][now.y]<now.w)continue;
for(ll i=0; i<4; i++)
{
ll xx=now.x+go[i][0];
ll yy=now.y+go[i][1];
if(xx>=1&&xx<=n&&yy>=1&&yy<=n-xx+1&&dp[now.x][now.y]+e[xx][yy]<dp[xx][yy])
{
dp[xx][yy]=dp[now.x][now.y]+e[xx][yy];
q.push(node(xx,yy,dp[xx][yy]));
}
}
}
}
ll dfs(ll x,ll y)
{
if(step[x][y])return step[x][y];
ll sum=0;
for(ll i=0; i<4; i++)
{
ll xx=x+go[i][0];
ll yy=y+go[i][1];
if(xx>=1&&xx<=n&&yy>=1&&yy<=n-xx+1&&dp[x][y]==dp[xx][yy]+e[x][y])
sum+=dfs(xx,yy)%mod;
}
return step[x][y]=sum;
}
int main()
{
while(scanf("%lld",&n)&&n)
{
for(ll i=1; i<=n; i++)
for(ll j=1; j<=n; j++)
scanf("%lld",&e[i][j]);
for(ll i=1; i<=n; i++)
for(ll j=n-i; j>=1; j--)
{
ll x=n-j+1;
ll y=n-i+1;
e[i][j]+=e[x][y];
}
mem(dp,inf);
mem(step,0);
bfs();
ll minn=inf;
for(ll i=1; i<=n; i++)
minn=min(minn,dp[i][n-i+1]);
step[1][1]=1;
ll ans=0;
for(ll i=1; i<=n; i++)
if(dp[i][n-i+1]==minn)
ans+=dfs(i,n-i+1)%mod;
printf("%lld\n",ans);
}
return 0;
}