题意:给你一个矩阵,按照副对角线对称的路径从(0,0)走到(n-1,n-1)的最小价值的路径数;
矩阵的每一个点aij代表价值;
思路:将矩阵的下半部加到上半部,这样只要走到副对角线即可;
先SPFA求d[i][j]表示走到i,j这个点的最小价值,得到d[i][n-i-1]的价值,
找出最小价值minn的点(i,n-i-1),从这个点回溯到(0,0)求出有多少路径,即为答案。
#include <stdio.h>
#include <string.h>
#include <vector>
#include <queue>
#include <algorithm>
#include <iostream>
using namespace std;
#define N 1005
#define INF 1000000000
#define MOD 1000000009
int m[4][2]={-1,0,0,1,1,0,0,-1};
int n,mat[105][105];
struct node
{
int x,y,dis;
friend bool operator<(node a,node b)
{
return a.dis > b.dis;
}
};
bool Isok(int x,int y)
{
if(x>=0&&x<n&&y>=0&&y<n&&(x+y)<n) return true;
return false;
}
int vis[105][105],d[105][105];
void SPFA()//初始d[i][j]
{
memset(vis,0,sizeof(vis));
int i, j, dx, dy;
for (i = 0; i < n; i++)
for (j = 0; j < n-i; j++)
d[i][j] = INF;
node p,q;
d[0][0]=mat[0][0];
p.x=0;p.y=0;p.dis=mat[0][0];
priority_queue<node>Q;
Q.push(p);
while(!Q.empty())
{
q=Q.top();
Q.pop();
if(vis[q.x][q.y])
continue;
vis[q.x][q.y]=1;
for (i=0;i<4;i++)
{
dx=q.x+m[i][0];
dy=q.y+m[i][1];
if(!Isok(dx,dy))
continue;
if(d[dx][dy]-mat[dx][dy]>q.dis)
{
d[dx][dy]=mat[dx][dy]+q.dis;
p.x=dx;p.y=dy;p.dis=d[dx][dy];
Q.push(p);
}
}
}
}
int dfs(int x,int y)
{
int res=0;
if(x==0&&y==0)//搜到(0,0),则找到一条路径;
return 1;
for(int i=0;i<4;i++)
{
int dx=x+m[i][0];
int dy=y+m[i][1];
if(!Isok(dx,dy))
continue;
if(d[x][y]==d[dx][dy]+mat[x][y])//关键:要满足(x,y)的上一点是(dx,dy)
res=(res+dfs(dx,dy))%MOD;
}
return res;
}
int main()
{
while(scanf("%d", &n))
{
if(n==0) break;
int i,j;
for (i = 0;i < n; i++)
for (j = 0;j < n;j++)
scanf("%d", &mat[i][j]);
for (i = 0; i < n; i++)
for (j = 0; j < n-i-1; j++)
mat[i][j] += mat[n-j-1][n-i-1];
SPFA();
int minn=INF;
int ans=0;
for(i=0;i<n;i++)
if(d[i][n-i-1]<minn)
minn=d[i][n-i-1];//找出最小的价值;
for(i=0;i<n;i++)
if(d[i][n-i-1]==minn)//从最小的价值往回搜
ans=(ans+dfs(i,n-i-1))%MOD;
printf("%d\n",ans);
}
return 0;
}
/*
3
1 2 3
2 1 3
1 1 2
*/