您的位置:首页 > 其它

uva 10201 - Adventures in Moving - Part IV

2014-08-04 23:52 369 查看

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,因为这个是转移的初态。并且[b]p[0].dis=0,这个在转移时要使用到的。[/b]

代码:

#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]}。

不愧是大牛啊!膜拜!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: