桐爷开车 线性动态规划

探讨了如何通过动态规划解决桐爷驾车从深圳到帝都的油耗最小化问题,利用线性动态规划和类似背包问题的方法,计算了在考虑多个油站不同油价情况下的最优加油策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述

桐爷人称计科老司机,有天要从深圳跑长途去帝都。桐爷的塞恩车每跑一千米耗油一升。塞恩车的油箱容量为200升。桐爷出发时有100升油,为了造成少耗油的假象到达帝都时至少有100升油。沿途有不少加油站,但是大多都是黑油站,油的价格差别大。桐爷心算了达帝都时的最小花费,请你也计算一下,看你是否能算对,有老司机的潜质。

输入

第一行是深圳到帝都的距离(小于10000千米),接着是不多于100个的黑油站的信息,按离深圳由近到远排列,包括油站到深圳的距离和每升油的价格(不超过2000)。

样例输入

500
100 999
150 888
200 777
300 999
400 1009
450 1019
500 1399

输出

桐爷到帝都的最小花费。如果不能按要求到达,输出Impossible

样例输出

450550

题解

一开始老师就跟我们说了这道题是线性动态规划,想了好久,想动态转移方程,后面发现这道题跟背包有点像。

动态转移方程如下:
dp[i][j] = min( dp[i][ j ] , dp[i-1][j+w-k ]+k*p[i] )这边的动态转移方程含义是:在第i个加油站加完k升油后具有j升油。

其中w为第i个油站和第i-1个油站之间的距离。

这边比较难理解的就是j+w-k,由于我已经说明j表示的是在第i个加油站加完油后的油量。那么j-k就代表到达第i个油站后尚未加油的状态,那么j-k+w就代表在第i-1个油站要出发往第i个油站的状态,也可简单理解为在第i-1个油站。

那么再次强调一下动态转移方程dp[i][j] = min( dp[i][ j ] , dp[i-1][j+w-k ]+k*p[i] )就表示我在第i个油站加油或不加油的最小话费金额。

注意由于油箱容量为200,所以任何时刻油量都不能超过200。

代码实现

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define INF 1e9
int len,n=1;
int dp[100+5][200+5];
int dist[100+5];//第i个站的距离
int p[100+5];   //第i个站的价格

int main(){
    cin >> len;
    for(n = 1; 2==scanf("%d%d",&dist[n],&p[n]);n++);
    n--;
	
	//初始状态dp中的元素初始为无穷大
    for(int i=0;i<=n;i++)
    	for(int j=0;j<=200;j++)
        	dp[i][j]=INF;
    /*
    出发点时,花费为0,注意出发时不是在第1个油站哦,
    出发点的下一个目标点才是油站,
    注意,第一个油站的下标值是从1开始的,不是0开始。
    */
    dp[0][100]=0;

    //DP递推过程
    for(int i=1; i<=n; i++){
        //第i站与第i-1站的距离差值
        int w=dist[i]-dist[i-1];
        //j从0-200枚举,j表示在第i个油站出发时油的容量
        for(int j=0; j<=200; j++){
        	//k表示在第i个油站加了多少油
            for(int k=0; k<=j; k++)
           /*
     		j+w-k:在第i-1个油站出发的油量且其油量不能多于200
     		(赛恩车油箱容量为200)
     		*/
            if(j+w-k<=200 ){
            	//加和不和的话费不同,我们选择话费较小的
                dp[i][j]=min(dp[i][j],
                    dp[i-1][j+w-k]+k*p[i]);
            }
        }
    }
	/*
	解释一下下面的判断,由于dist数组存储的是深圳到油站的距离,
	len表示深圳到北京的距离,
	如果深圳到北京的距离-深圳到最后一个油站的距离大于100,那么桐爷就到不了北京了
	仔细思考一下,就能想明白的。(因为我们到北京时车里还需要有100升的汽油)
	*/
    if(len-dist[n]>100
        || dp[n][100+len-dist[n]]==INF)
        printf("Impossible\n");
    else
    	//能够到达北京,并且车里有100升油的最小花费。
        printf("%d\n",dp[n][100+len-dist[n]]);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值