题目需要好好读懂......(不看题解就卡住了)
先求出各个点到(n, n)的最短距离(通过这个题还掌握了bfs求全局各个点到某一终点的距离 ,巧妙)。
然后搜索 + 记忆化。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn = 60;
const int inf = 1e9;
int dis[maxn][maxn];
int sum[maxn][maxn];
int dir[4][2] = {{-1, 0}, {0, -1}, {0, 1}, {1,0}};
int n;
struct Node
{
int x, y;
Node(int xx, int yy)
{
x = xx; y = yy;
}
};
bool vis[maxn][maxn];
ll dp[maxn][maxn];
bool judge(int x, int y)
{
if(x < 1 || x > n || y < 1 || y > n) return false;
return true;
}
void bfs() //巧妙! 求每个点到(n, n)的最短路
{
queue<Node> q;
sum[n][n] = dis[n][n];
vis[n][n] = 1;
q.push(Node(n, n));
while(!q.empty())
{
Node top = q.front(); q.pop();
int curx = top.x, cury = top.y;
vis[curx][cury] = 0; //can ignore
//cout << curx << " " << cury << ": " << sum[curx][cury] << endl;
for(int i = 0; i < 4; i++)
{
int nx = curx + dir[i][0];
int ny = cury + dir[i][1];
if(judge(nx, ny))
{
if(sum[nx][ny] > sum[curx][cury] + dis[nx][ny])
{
sum[nx][ny] = sum[curx][cury] + dis[nx][ny];
if(!vis[nx][ny]) //
{
//cout << "push " << nx << " " << nx << endl;
q.push(Node(nx, ny));
vis[nx][ny] = 1;
}
}
}
}
}
}
ll dfs(int x, int y)
{
//if(x < 1 || x > n || y < 1 || y > n) return 0;
if(dp[x][y] != -1)
return dp[x][y];
if(x == n && y == n)
return 1;
int ret = 0;
for(int i = 0; i < 4; i++)
{
//int num = 0;
int nx = x + dir[i][0];
int ny = y + dir[i][1];
if(judge(nx, ny) && sum[nx][ny] < sum[x][y])
{
ret += dfs(nx, ny);
}
}
return dp[x][y] = ret;
}
int main()
{
while(scanf("%d", &n) == 1)
{
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= n; j++)
{
cin >> dis[i][j];
sum[i][j] = inf;
}
}
bfs();
memset(vis, 0, sizeof(vis));
memset(dp, -1, sizeof(dp));
ll ans = dfs(1, 1);
cout << ans << endl;
}
return 0;
}