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

题目描述

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

输入格式

第一行,\(D1\)\(C\)\(D2\)\(P\)\(N\)

接下来有\(N\)行。

\(i+1\) 行,两个数字,油站\(i\)离出发点的距离\(D_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 \le 6\) \(,\) 其余数字 \(\le 500\)

思路

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

\(D_{i+1}=D_i+1,P_{i+1}\lt P_{i}\)

\(D_{i+2}=D_i+2,P_{i+2}\lt P_{i+1}\)

\(D_{i+3}=D_i+3,P_{i+3}\lt P_{i+2}\)

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

比较一下以下两种方案:

  1. 直接从 \(i\)\(i+3\)
  2. \(i\)\(i+1\) ,从 \(i+1\)\(i+2\) ,从 \(i+2\)\(i+3\)

应该是方案 \(2\) 更好。

所以,只要在这个点所能到达的点中直接跳到离这个点最近的并且 \(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\) 小,那就应该加满油,到下一个点的时候稍加一点油,就会更划算。

代码

#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

posted @ 2022-06-10 18:39  A_zjzj  阅读(23)  评论(0编辑  收藏  举报