优化青海湖至景点X的租车路线成本题解 | 豆包MarsCode AI刷题

51 阅读4分钟

题解:

屏幕截图 2024-11-21 224524.png


思路解析:
目标是在给定的距离和若干个加油站的情况下,找到从起点到终点所需的最小花费,这个题可以用状态标识,所以可以用动态规划。因为这个题不考虑次序,首先,我们将起点和终点分别添加到加油站列表中,并进行排序。对状态(i,j),j表示由远及近到第i个油站选择加油或不加油后的油量。状态转移方程(i,j)=min((i-1,j+距上次加油站的距离),(i-1,j+距上次加油站的距离-这个油站加的油)+这个加油站加的油x这个加油站的油价)

这种动态规划方法的时间复杂度主要取决于加油站的数量和油量范围,整体上是可接受的。通过这种方式,我们可以有效地找到最小的加油花费,同时保证车辆能够顺利到达目的地。

注意:
这个题要在数据集头尾加上起点和终点方便计算
当数到第n个逻辑单列
让j+距上次加油站的距离,j+距上次加油站的距离-这个油站加的油小于400才能执行比较

具体步骤

  • 数据预处理

    • 添加起点和终点:在数据集中添加起点(距离为0)和终点(距离为总距离)。
    • 排序:将所有加油站按距离从小到大排序。
  • 定义状态

    • 状态定义:定义一个二维动态规划数组dp[i][j],其中 i 表示当前加油站的索引,j 表示当前剩余油量。dp[i][j] 表示到达第 i 个加油站时,剩余油量为 j 升的最小花费。
  • 初始化

    • 初始状态:将起点的油量设为200升,花费设为0,即 dp[0][200] = 0。
  • 状态转移

    • 遍历加油站:遍历每一个加油站,从第一个加油站开始。
    • 不加油的情况:计算不加油时的剩余油量,并更新 dp[i][j]。
    • 加油的情况:遍历所有可能的加油量 k,计算加油后的剩余油量,并更新 dp[i][j]。
  • 边界条件

    • 超出油箱限制:如果某段距离大于400升,则直接返回-1。

为了更好地实现上述动态规划方法,还需要明确边界条件和具体的状态转移细节。具体来说:

  • 边界条件:如果某个加油站之间的距离超过400公里(即车辆当前油量不足以覆盖这段距离),则直接返回 -1,表示无法完成旅行。

  • 状态转移方程:

    •   对于每个加油站 i 和每种可能的油量 j(从0400),状态转移方程如下:
      
    •   不加油的情况:dp[i][j] = min(dp[i][j], dp[i-1][j - (dist[i] - dist[i-1])])
      
    •    加油的情况:对于每个加油站 i 和每个可能的加油量 k(从0200),状态转移方程为: dp[i][j] = min(dp[i][j], dp[i-1][j + k - (dist[i] - dist[i-1])] + k * price[i])
      
    •   其中,dist[i] 表示第 i 个加油站到起点的距离,price[i] 表示第 i 个加油站的油价。
      
  • 结果提取:最终的答案应该是 dp[n][200],即到达最后一个加油站时,油量为200升时的最小花费。

通过以上步骤,我们可以有效地解决加油问题,并确保在满足车辆行驶距离限制的前提下,找到最小的加油花费。

int solution(int distance, int n, std::vector<std::vector<int>> gas_stations) {
    sort(gas_stations.begin(), gas_stations.end());
    gas_stations.insert(gas_stations.begin(), { 0, 0 });
    gas_stations.push_back({ distance, 0 });
    n++;
    vector<vector<long long>> dp(n + 1, vector<long long>(405, Max));
    dp[0][200] = 0; 
    for (int i = 1; i <= n; i++) {
        int dist = gas_stations[i][0] - gas_stations[i - 1][0]; 
        if (dist > 400) {
            return -1;
        }
        for (int j = 0; j <= 400; j++) {
            if (i == n) {
                if(j+dist<=400)dp[i][200] = min(dp[i][200], dp[i - 1][200 + dist]);
                continue;
            }
            for (int k = 0; k <= j; k++) { 
                if (j - k + dist <= 400) { 
                    dp[i][j] = min(dp[i][j], dp[i - 1][j + dist - k] + k * gas_stations[i][1]);
                }
                if (j + dist <= 400) {
                    dp[i][j] = min(dp[i][j], dp[i - 1][j + dist]);
                }
            }
        }
    }
    //for(int i=0;i<=400;i++)cout<<i<<" "<< dp[n][i] << endl;
    //cout<< (dp[n][200] == Max ? -1 : dp[n][200])<<endl;
    return dp[n][200] == Max ? -1 : dp[n][200];
}