uva 10201 - Adventures in Moving - Part IV

Problem A: Adventures in Moving - Part IV

To help you move from Waterloo to the big city, you are considering renting a moving truck. Gas prices being so high these days, you want to know how much the gas for such a beast will set you back.

The truck consumes a full litre of gas for each kilometre it travels. It has a 200 litre gas tank. When you rent the truck in Waterloo, the tank is half full. When you return it in the big city, the tank must be at least half full, or you'll get gouged even more for gas by the rental company. You would like to spend as little as possible on gas, but you don't want to run out along the way.

Input

The input begins with a single positive integer on a line by itself indicating the number of the cases following, each of them as described below. This line is followed by a blank line, and there is also a blank line between two consecutive inputs.

Input is all integers. The first integer is the distance in kilometres from Waterloo to the big city, at most 10000. Next comes a set of up to 100 gas station specifications, describing all the gas stations along your route, in non-decreasing order by distance. Each specification consists of the distance in kilometres of the gas station from Waterloo, and the price of a litre of gas at the gas station, in tenths of a cent, at most 2000.

Output

For each test case, the output must follow the description below. The outputs of two consecutive cases will be separated by a blank line.

Output is the minimum amount of money that you can spend on gas to get you from Waterloo to the big city. If it is not possible to get from Waterloo to the big city subject to the constraints above, print "Impossible".

Sample Input

1

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

Output for Sample Input

450550

这道题算简单的了,阶段非常明显。但是处理要小心。dp[i][j]表示前i个站还剩j升油的最小费用。

dp[i][j]=min{dp[i-1][k]+(j-k+d)*p[i].price}, 这里d=p[i].dis-p[i-1].dis,当然d>200时显然无解,可以continue使得dp[i][0...200]均为inf,导致后面无法正常转移,最后就是无解的,这是个技巧。还有d<=k<=j+d,因为k<d说明半路油用完了,k>j+d说明到第i站剩余油量大于j升,这些显然都是不合法的。还有如果j+d>200了,k却不能超过200,因此设置上限k<=min(j+d,200).还有初始化所有值为inf,但dp[0][100]=0,因为这个是转移的初态。并且p[0].dis=0,这个在转移时要使用到的。


代码:

#include<cstdio>
#include<iostream>
using namespace std;

struct station{
    int dis,price;
}p[110];
int dp[110][210];
char s[20];
const int inf=1<<30;
int main()
{
    int t,n,cas=0;
    scanf("%d",&t);
    while(t--){
        if(cas++) puts("");
        scanf("%d%*c",&n);
        int tot=1;
        while(gets(s)&&s[0]){
            sscanf(s,"%d%d",&p[tot].dis,&p[tot].price);
            tot++;
        }
        p[0].dis=0;
        for(int i=0;i<=200;i++) dp[0][i]=inf;
        dp[0][100]=0;
        for(int i=1;i<tot;i++)
            for(int j=0;j<=200;j++){
                dp[i][j]=inf;
                int dis=p[i].dis-p[i-1].dis;
                if(dis>200) continue;
                for(int k=dis;k<=min(200,j+dis);k++)
                    dp[i][j]=min(dp[i][j],dp[i-1][k]+(j+dis-k)*p[i].price);
            }
        int d=n-p[tot-1].dis;
        if(d>100||dp[tot-1][d+100]==inf)
            printf("Impossible\n");
        else
            printf("%d\n",dp[tot-1][d+100]);
    }
	return 0;
}


在网上闲逛的时候突然看到了O(n^2)的解法。有点吓傻了。

我们不妨用f[i][j]表示到第i个加油站油量为j时这个状态所需的最小花费,那么首先有一部分状态是从第i-1个加油站继承过来的,即f[i][j]=f[i-1][j+d[i]-d[i-1]],之后就是考虑在第i个加油站买多少油会更划算,那么状态转移方程为f[i][j]=min{min{f[i][k]+(j-k)*m[i]},f[i][j]},这样乍看上去是三个for,然而对于min{f[i][k]+(j-k)*m[i]}这个部分,实际上我们也可以写成f[i][k]-k*m[i]+j*m[i],而f[i][k]-k*m[i]这个部分仅和k有关,我们可以在循环j的时候顺便记录下最小的f[i][j]-j*m[i]即可,不妨设为temp,那么第二个动态转移方程就变成了f[i][j]=min{min{temp+j*m[i]},f[i][j]}。

不愧是大牛啊!膜拜!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值