题意:一个 n x n 的矩阵(2=<n<=50),矩阵中的每个元素代表在这个位置上要花的时间(0<t<=50),现要从(1, 1) 去到(n, n),在走的过程中,如果走一步,则到达的位置到(n, n)的最短路要比当前位置到达(n, n)的最短路要短。问到达(n, n)有多少种走法。
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1428
——>>题目有点绕。。所说的最短路是从终点往回推的最短路。。
先 bfs 求出各点到(n, n)的最短路,再dp。。
状态:dp[i][j] 表示从 (i, j) 到(n, n)的路径数
#include <cstdio>
#include <queue>
#include <cstring>
using std::priority_queue;
const int MAXN = 50 + 10;
const int dx[] = {-1, 1, 0, 0};
const int dy[] = { 0, 0, -1, 1};
struct NODE
{
int x;
int y;
long long t;
NODE(int x = 0, int y = 0, long long t = 0) : x(x), y(y), t(t){}
bool operator < (const NODE& e) const
{
return t > e.t;
}
};
int n;
long long G[MAXN][MAXN];
long long Time[MAXN][MAXN];
long long dp[MAXN][MAXN];
void Read()
{
for (int i = 1; i <= n; ++i)
{
for (int j = 1; j <= n; ++j)
{
scanf("%I64d", &G[i][j]);
}
}
}
void Bfs()
{
priority_queue<NODE> qu;
memset(Time, -1, sizeof(Time));
qu.push(NODE(n, n, G[n][n]));
Time[n][n] = G[n][n];
while (!qu.empty())
{
NODE u = qu.top();
qu.pop();
for (int i = 0; i < 4; ++i)
{
int newx = u.x + dx[i];
int newy = u.y + dy[i];
if (newx >= 1 && newx <= n && newy >= 1 && newy <= n && Time[newx][newy] == -1)
{
Time[newx][newy] = u.t + G[newx][newy];
qu.push(NODE(newx, newy, Time[newx][newy]));
}
}
}
}
void Init()
{
memset(dp, -1, sizeof(dp));
dp[n][n] = 1;
}
long long Dp(int x, int y)
{
long long& ans = dp[x][y];
if (ans != -1) return ans;
ans = 0;
for (int i = 0; i < 4; ++i)
{
int newx = x + dx[i];
int newy = y + dy[i];
if (newx >= 1 && newx <= n && newy >= 1 && newy <= n && Time[newx][newy] < Time[x][y])
{
ans += Dp(newx, newy);
}
}
return ans;
}
void Solve()
{
printf("%I64d\n", Dp(1, 1));
}
int main()
{
while (scanf("%d", &n) == 1)
{
Read();
Bfs();
Init();
Solve();
}
return 0;
}
状态转移方程:dp[i][j] += dp[x][y]。。(i, j) ——> (x, y) ——> (n, n)。。