统计所有可行路径
给你一个 互不相同 的整数数组,其中 locations[i]
表示第 i
个城市的位置。同时给你 start
,finish
和 fuel
分别表示出发城市、目的地城市和你初始拥有的汽油总量
每一步中,如果你在城市 i
,你可以选择任意一个城市 j
,满足 j != i
且 0 <= j < locations.length
,并移动到城市 j
。从城市 i
移动到 j
消耗的汽油量为 |locations[i] - locations[j]|
,|x|
表示 x
的绝对值。
请注意, fuel
任何时刻都 不能 为负,且你 可以 经过任意城市超过一次(包括 start
和 finish
)。
请你返回从 start
到 finish
所有可能路径的数目。
由于答案可能很大, 请将它对 10^9 + 7
取余后返回。
示例 1:
输入:locations = [2,3,6,8,4], start = 1, finish = 3, fuel = 5
输出:4
解释:以下为所有可能路径,每一条都用了 5 单位的汽油:
1 -> 3
1 -> 2 -> 3
1 -> 4 -> 3
1 -> 4 -> 2 -> 3
示例 2:
输入:locations = [4,3,1], start = 1, finish = 0, fuel = 6
输出:5
解释:以下为所有可能的路径:
1 -> 0,使用汽油量为 fuel = 1
1 -> 2 -> 0,使用汽油量为 fuel = 5
1 -> 2 -> 1 -> 0,使用汽油量为 fuel = 5
1 -> 0 -> 1 -> 0,使用汽油量为 fuel = 3
1 -> 0 -> 1 -> 0 -> 1 -> 0,使用汽油量为 fuel = 5
示例 3:
输入:locations = [5,2,1], start = 0, finish = 2, fuel = 3
输出:0
解释:没有办法只用 3 单位的汽油从 0 到达 2 。因为最短路径需要 4 单位的汽油。
提示:
2 <= locations.length <= 100
1 <= locations[i] <= 109
- 所有
locations
中的整数 互不相同 。 0 <= start, finish < locations.length
1 <= fuel <= 200
代码:
//记忆化搜索
class Solution {
private:
static constexpr int mod = 1000000007;
vector<vector<int>> f;
public:
int dfs(const vector<int>& locations, int pos, int finish, int rest) {
if (f[pos][rest] != -1) {
return f[pos][rest];
}
f[pos][rest] = 0;
if (abs(locations[pos] - locations[finish]) > rest) {
return 0;
}
int n = locations.size();
for (int i = 0; i < n; ++i) {
if (pos != i) {
if (int cost = abs(locations[pos] - locations[i]); cost <= rest) {
f[pos][rest] += dfs(locations, i, finish, rest - cost);
f[pos][rest] %= mod;
}
}
}
if (pos == finish) {
f[pos][rest] += 1;
f[pos][rest] %= mod;
}
return f[pos][rest];
}
int countRoutes(vector<int>& locations, int start, int finish, int fuel) {
f.assign(locations.size(), vector<int>(fuel + 1, -1));
return dfs(locations, start, finish, fuel);
}
};
//DP
/*
状态: dp[f][i]表示消耗了f燃料, 到达城市i的路径数
转移方程: dp[f][i] = dp[f][i] + dp[f - dis][j] 其中 j != i,dis是城市i, j距离的绝对值
初始化: dp[0][start] = 1, 表示初始时, 在start位置, 不用消耗任何燃料, 路径数自然为1
*/
class Solution {
public:
int M = 1000000007;
int countRoutes(vector<int>& locations, int start, int finish, int fuel) {
int n = locations.size();
//到达第i个城市,还剩j格油的方案数
vector<vector<int>> dp(n, vector<int>(fuel+1, 0));
dp[start][fuel] = 1;
for(int i = fuel-1; i >= 0; --i)
{
for(int j = 0; j < n; ++j)
{
for(int k = 0; k < n; ++k)
{
if(j == k)
continue;
//从k出发,到j,还剩i的油
int dist = abs(locations[j] - locations[k]);
if(i + dist <= fuel)
{
dp[j][i] += dp[k][i+dist];
dp[j][i] %= M;
}
}
}
}
int res = 0;
for(int i = 0; i <= fuel; ++i)
{
res += dp[finish][i];
res %= M;
}
return res;
}
};
//优化DP
class Solution {
private:
static constexpr int mod = 1000000007;
public:
int countRoutes(vector<int>& locations, int start, int finish, int fuel) {
int n = locations.size();
int startPos = locations[start];
int finishPos = locations[finish];
sort(locations.begin(), locations.end());
for (int i = 0; i < n; ++i) {
if (startPos == locations[i]) {
start = i;
}
if (finishPos == locations[i]) {
finish = i;
}
}
vector<vector<int>> dpL(n, vector<int>(fuel + 1));
vector<vector<int>> dpR(n, vector<int>(fuel + 1));
dpL[start][0] = dpR[start][0] = 1;
for (int used = 0; used <= fuel; ++used) {
for (int city = n - 2; city >= 0; --city) {
if (int delta = locations[city + 1] - locations[city]; used >= delta) {
dpL[city][used] = ((used == delta ? 0 : dpL[city + 1][used - delta]) * 2 % mod + dpR[city + 1][used - delta]) % mod;
}
}
for (int city = 1; city < n; ++city) {
if (int delta = locations[city] - locations[city - 1]; used >= delta) {
dpR[city][used] = ((used == delta ? 0 : dpR[city - 1][used - delta]) * 2 % mod + dpL[city - 1][used - delta]) % mod;
}
}
}
int ans = 0;
for (int used = 0; used <= fuel; ++used) {
ans += (dpL[finish][used] + dpR[finish][used]) % mod;
ans %= mod;
}
if (start == finish) {
ans = (ans + mod - 1) % mod;
}
return ans;
}
};