洛谷P1016旅行家的预算题解--zhengjun

题目描述

一个旅行家想驾驶汽车以最少的费用从一个城市到另一个城市(假设出发时油箱是空的)。给定两个城市之间的距离 D 1 D1 、汽车油箱的容量 C C (以升为单位)、每升汽油能行驶的距离 D 2 D2 、出发点每升汽油价格 P P 和沿途油站数 N N N N 可以为零),油站 i i 离出发点的距离 D i D_i 、每升汽油价格 P i P_i i = 1 , 2 , , N i=1,2,…,N )。计算结果四舍五入至小数点后两位。如果无法到达目的地,则输出No Solution

输入格式

第一行, D 1 D1 C C D 2 D2 P P N N

接下来有 N N 行。

i + 1 i+1 行,两个数字,油站 i i 离出发点的距离 D i D_i 和每升汽油价格 P i P_i

输出格式

所需最小费用,计算结果四舍五入至小数点后两位。如果无法到达目的地,则输出No Solution

输入输出样例

输入 #1
275.6 11.9 27.4 2.8 2
102.0 2.9
220.0 2.2
输出 #1
26.95

说明/提示

N 6 N \le 6 , , 其余数字 500 \le 500

思路

我一开始做的时候,这么水的模拟+贪心题怎么是绿题。
就开始了。
首先,如果在这个点能够到达的点中没有比这个点的 P P 更小的了,就找一个最小的开过去。
可是还有一个误区,就是这样:

D i + 1 = D i + 1 , P i + 1 < P i D_{i+1}=D_i+1,P_{i+1}\lt P_{i}

D i + 2 = D i + 2 , P i + 2 < P i + 1 D_{i+2}=D_i+2,P_{i+2}\lt P_{i+1}

D i + 3 = D i + 3 , P i + 3 < P i + 2 D_{i+3}=D_i+3,P_{i+3}\lt P_{i+2}

这些都是点 i i 能够到达的点。

比较一下以下两种方案:

  1. 直接从 i i i + 3 i+3
  2. i i i + 1 i+1 ,从 i + 1 i+1 i + 2 i+2 ,从 i + 2 i+2 i + 3 i+3

应该是方案 2 2 更好。

所以,只要在这个点所能到达的点中直接跳到离这个点最近的并且 P x < P i P_x\lt P_i 的点上就可以了。

代码

#include<bits/stdc++.h>
#define maxn 10000 
using namespace std;
double l,c,d,p[maxn],w[maxn];
int n;
int main(){
    scanf("%lf%lf%lf%lf%d",&l,&c,&d,&p[0],&n);
    w[0]=0;
    double x=c*d; 
    for(int i=1;i<=n;i++){
    	scanf("%lf%lf",&w[i],&p[i]);
    	if(w[i]-w[i-1]>x){
    		cout<<"No Solution";
    		return 0;
		}
	}
	w[++n]=l;
	p[n]=0x3fffffff;
	double ans=0;
	int now=0;
	while(now!=n){
		int k=now;
		for(int j=now+1;j<=n&&w[j]-w[now]<=x;j++)
			if(p[j]<=p[k]||j==n){
				k=j;
				break;//第一个!!!
			}
		if(k==now){//没有比P{now}更小的Px了
			k=now+1;
			for(int j=now+2;j<=n&&w[j]-w[now]<=x;j++)
				if(p[j]<=p[k]){
					k=j;
				}
		}
		ans+=(w[k]-w[now])/d*p[now];
		now=k;
	}
	printf("%0.2lf",ans);
	return 0;
}

别急着抄代码,这还不是正解。

因为,还有一种情况,如果你要去的下一个点的 P P 比当前点的 P P 小,那就应该加满油,到下一个点的时候稍加一点油,就会更划算。

代码

#include<bits/stdc++.h>
#define maxn 8 
using namespace std;
double l,c,d,p[maxn],w[maxn];
double y[maxn];
int n;
int main(){
    scanf("%lf%lf%lf%lf%d",&l,&c,&d,&p[0],&n);
    w[0]=0;
    double x=c*d; 
    for(int i=1;i<=n;i++){
    	scanf("%lf%lf",&w[i],&p[i]);
    	if(w[i]-w[i-1]>x){
    		cout<<"No Solution";
    		return 0;
		}
	}
	w[++n]=l;
	p[n]=0x3fffffff;
	double ans=0,youliang=0;
	int now=0;
	while(now!=n){
		int k=now;
		for(int j=now+1;j<=n&&w[j]-w[now]<=x;j++){
			if(p[j]<=p[k]||j==n){
				k=j;
		        ans+=((w[k]-w[now])/d-youliang)*p[now];
		        youliang=0;
				break;
			}
		}
		if(k==now){
			k=now+1;
			for(int j=now+2;j<=n&&w[j]-w[now]<=x;j++)
				if(p[j]<=p[k]){
					k=j;
				}
			ans+=(c-youliang)*p[now];
			youliang=c-youliang-(w[k]-w[now])/d;
		}
		now=k;
	}
	printf("%0.2lf",ans);
	return 0;
}

谢谢–zhengjun

发布了48 篇原创文章 · 获赞 49 · 访问量 2153

猜你喜欢

转载自blog.csdn.net/A_zjzj/article/details/104309185
今日推荐