13年安徽省赛题目。bfs处理出所有点到n,m点的最短距离,再dfs一次即可。
ps:在bfs时,加入v数组若i,j点已经在栈中则不必入栈,更新距离即可。避免重复入栈导致超时。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;
#define N 100
#define INF 1000000000
typedef long long LL;
int n, m;
LL dp[N][N];
int a[N][N];
int dis[N][N];
int v[N][N];
int s[1000000][2];
int ntr;
int ptr;
int mov[4][2] = {0, 1, 1, 0, -1, 0, 0, -1};
void init(){
memset(dp, 0, sizeof(dp));
memset(dis, -1, sizeof(dis));
memset(v, 0, sizeof(v));
ptr = 0;
ntr = 0;
}
void bfs(int i, int j){
for(int l = 0; l < 4; l ++){
int i0, j0;
i0 = i + mov[l][0];
j0 = j + mov[l][1];
if(i0 < 1 || j0 < 1 || i0 > n || j0 > m)continue;
if(dis[i0][j0] == -1 || (dis[i][j] + a[i0][j0] < dis[i0][j0])){
dis[i0][j0] = dis[i][j] + a[i0][j0];
if(!v[i0][j0]){
s[ptr][0] = i0;
s[ptr][1] = j0;
v[i0][j0] = 1;
ptr ++;
}
}
}
}
LL dfs(int i, int j){
if(dp[i][j]) return dp[i][j];
LL ans = 0;
for(int l = 0; l < 4; l ++){
int i0, j0;
i0 = i + mov[l][0];
j0 = j + mov[l][1];
if(i0 < 1 || j0 < 1 || i0 > n || j0 > m)continue;
if(dis[i0][j0] < dis[i][j]) {
ans += dfs(i0, j0);
}
}
return dp[i][j] = ans;
}
int main(){
while(scanf("%d%d", &n, &m) != EOF){
init();
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
scanf("%I64d", &a[i][j]);
}
}
dis[n][m] = 0;
s[ptr][0] = n;
s[ptr][1] = m;
v[n][m] = 1;
ptr ++;
while(ntr < ptr){
bfs(s[ntr][0], s[ntr][1]);
v[s[ntr][0]][s[ntr][1]] = 0;
ntr ++;
}
dp[n][m] = 1;
printf("%I64d\n", dfs(1, 1));
}
return 0;
}