UVA 10201 Adventures in Moving - Part IV(动态规划)

273 篇文章 0 订阅
112 篇文章 0 订阅

UVA 10201 Adventures in Moving - Part IV(动态规划)

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1142

题意:

       有一辆车,原始装有100L汽油,到达距离为d的目的地,中间有x个加油站,每升油的价格为p。汽车每跑一公里耗油1L,求到达目的地油箱仍然有100L的最小花费。

分析:

       这道题目真是醉了,DP不难,但是细节太多了。

       本题一看有点类似于01背包问题。首先我们要知道如何定义一辆车的状态?

       一辆车的状态只与(它当前所在的加油站编号它当前还剩多少油)这两个因素有关,所以我们如下定义dp状态:

       dp[i][j]==x表示车正好刚走过第i个加油站后(可能在i站加了油,也可能没有)且还剩j升油时 花费的最小费用为x。

      

       初始状态dp全为INF,且dp[0][100]=0.

       假设车在第i个站加了k升油之后具有j升油 (k>=0) ,那么有下面的状态转移公式:(w为dist[i]-dist[i-1]的值,即w是从上一站走到下一站的距离)

       dp[i][j] = min( dp[i][ j ] , dp[i-1][j+w-k ]+k*p[i] )

       最终我们所求为dp[n][100]的值。

       本题不能用的滚动数组。

 

       注意由于油箱容量为200,所以任何时刻油量都不能超过200.令 w为dist[i]-dist[i-1]的值(即w是从上一站走到下一站的距离)。有下面几种情况需要注意:

1.    状态j的枚举为[0,200]范围。

2.    假设车在第i个站加了k升油之后具有j升油,那么车刚到i站时有j-k升油且车离开i-1站的那一刻有j-k+w升油。这里需要注意的是 k<=j j-k<=200 j-k+w<=200

3.    当车最后到达第n个站时,并不代表它到了终点。可能还需要走一段距离,这时候需要看这段距离x+100保存油量是否<=200,且还要看dp[n][100+x]是否<INF(想想为什么)

4.    初始距离就大于目的距离的站点不用考虑。因为走不到那么远。

5.    由于输入没有结束标志,只能处理每行字符串,所以这里很容易出错。

AC代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

#define INF 1e9
int n;
int dp[100+5][200+5];
int dist[100+5];//第i个站的距离
int p[100+5];   //第i个站的价格
int len;

int main()
{
    char str[100];
    gets(str);    //读数据组数
    int T;
    sscanf(str,"%d",&T);
    gets(str);//读空行
    for(int kase=1;kase<=T;kase++)
    {
        if(kase>1) printf("\n");//空行

        //读输入数据
        dist[0]=0;
        n=0;
        gets(str);
        sscanf(str,"%d",&len);
        while(gets(str))
        {
            if(str[0]=='\0') break;
            n++;
            sscanf(str,"%d %d",&dist[n],&p[n]);
            if(dist[n]>len) n--;//距离大于目的距离的站不用考虑
        }

        //初始化
        for(int i=0;i<=n;i++)
        for(int j=0;j<=200;j++)
            dp[i][j]=INF;
        dp[0][100]=0;

        //DP递推过程
        for(int i=1; i<=n; i++)
        {
            int w=dist[i]-dist[i-1];//第i站与第i-1站的距离差值
            for(int j=0; j<=200; j++)
            {
                for(int k=0; k<=j; k++)
                if(j+w-k<=200 )//&& dp[i-1][j+w-k]!=INF
                {
                    dp[i][j]=min(dp[i][j], dp[i-1][j+w-k]+k*p[i]);
                }
            }
        }

        //打印结果
        if(len-dist[n]>100 || dp[n][100+len-dist[n]]==INF)
            printf("Impossible\n");
        else
            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、付费专栏及课程。

余额充值