Problemsetter: Rujia Liu, Special Thanks: Yiming Li & Jane Alam Jan
找从左上角到右下角的,按y=x对称的路径,最短路径有多少条。
因为是对称的,所以只用找到y=x上的点的路径,可以先按对称性做一个预处理,把对称点的digit加起来。最后做最短路计数。
#include <cstdio> #include <algorithm> #include <vector> #include <map> #include <queue> #include <iostream> #include <stack> #include <set> #include <cstring> #include <stdlib.h> #include <cmath> using namespace std; typedef long long LL; typedef pair<int, int> P; const int maxn = 100 + 5; const int mod = 1000000000 + 9; int m[maxn][maxn]; int dp[maxn][maxn]; int countn[maxn][maxn]; int n; const int cx[] = {-1, 0, 1, 0}; const int cy[] = {0, 1, 0, -1}; bool valid(int x, int y){ return x < n && x >= 0 && y < n && y >= 0; } struct Node{ int x, y, dis; int lx, ly; Node(int x, int y, int dis, int lx, int ly){ this->x = x; this->y = y; this->dis = dis; this->lx = lx; this->ly = ly; } bool operator < (const Node &a) const{ return a.dis < dis; } }; void solve(){ priority_queue<Node> pq; for(int i = 0;i < maxn;i++) fill(dp[i], dp[i]+maxn, mod); countn[0][0] = 1; pq.push(Node(0, 0, m[0][0], 0, 0));// !!! while(!pq.empty()){ Node tem = pq.top();pq.pop(); int x = tem.x; int y = tem.y; int dis = tem.dis; int lx = tem.lx; int ly = tem.ly; if(dis < dp[x][y]){ dp[x][y] = dis; countn[x][y] = countn[lx][ly]; } else if(dis == dp[x][y]){ countn[x][y] = (countn[x][y] + countn[lx][ly]) % mod; continue; } else if(dis > dp[x][y]) continue; if(x + y == n-1) continue; for(int i = 0;i < 4;i++){ int tx = x + cx[i]; int ty = y + cy[i]; if(valid(tx, ty)){ pq.push(Node(tx, ty, dis+m[tx][ty], x, y)); } } } } int main(){ while(scanf("%d", &n) != EOF){ if(n == 0) break; for(int i = 0;i < n;i++){ for(int j = 0;j < n;j++){ scanf("%d", &m[i][j]); } } for(int i = 0;i < n;i++){ for(int j = 0;j < n-i-1;j++){ m[i][j] += m[n-j-1][n-i-1]; } } solve(); int Min = mod; for(int i = 0;i < n;i++){ Min = min(Min, dp[i][n-i-1]); } int ans = 0; for(int i = 0;i < n;i++){ if(dp[i][n-i-1] == Min) ans = (ans + countn[i][n-i-1]) % mod; } printf("%d\n", ans); } return 0; }