题意:给你一个矩阵,按照副对角线对称的路径从(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 */