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

题目描述

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

输入格式

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

接下来有 N N N行。

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

输出格式

所需最小费用,计算结果四舍五入至小数点后两位。如果无法到达目的地,则输出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 N6 , , , 其余数字 ≤ 500 \le 500 500

思路

我一开始做的时候,这么水的模拟+贪心题怎么是绿题。
就开始了。
首先,如果在这个点能够到达的点中没有比这个点的 P 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} Di+1=Di+1,Pi+1<Pi

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} Di+2=Di+2,Pi+2<Pi+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} Di+3=Di+3,Pi+3<Pi+2

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

比较一下以下两种方案:

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

应该是方案 2 2 2 更好。

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

代码

#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 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

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
对于洛谷上的p1036题目,我们可以使用Python来解决。下面是一个可能的解法: ```python def dfs(nums, target, selected_nums, index, k, sum): if k == 0 and sum == target: return 1 if index >= len(nums) or k <= 0 or sum > target: return 0 count = 0 for i in range(index, len(nums)): count += dfs(nums, target, selected_nums + [nums[i]], i + 1, k - 1, sum + nums[i]) return count if __name__ == "__main__": n, k = map(int, input().split()) nums = list(map(int, input().split())) target = int(input()) print(dfs(nums, target, [], 0, k, 0)) ``` 在这个解法中,我们使用了深度优先搜索(DFS)来找到满足要求的数列。通过递归的方式,我们遍历了所有可能的数字组合,并统计满足条件的个数。 首先,我们从给定的n和k分别表示数字个数和需要选取的数字个数。然后,我们输入n个数字,并将它们存储在一个列表nums中。接下来,我们输入目标值target。 在dfs函数中,我们通过迭代index来选择数字,并更新选取的数字个数k和当前总和sum。如果k等于0且sum等于target,我们就找到了一个满足条件的组合,返回1。如果index超出了列表长度或者k小于等于0或者sum大于target,说明当前组合不满足要求,返回0。 在循环中,我们不断递归调用dfs函数,将选取的数字添加到selected_nums中,并将index和k更新为下一轮递归所需的值。最终,我们返回所有满足条件的组合个数。 最后,我们在主程序中读入输入,并调用dfs函数,并输出结果。 这是一种可能的解法,但不一定是最优解。你可以根据题目要求和测试数据进行调试和优化。希望能对你有所帮助!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

A_zjzj

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值