CSP历年复赛题-P1016 [NOIP1999 普及组] 旅行家的预算
原题链接:https://www.luogu.com.cn/problem/P1016
题意解读:用最少的加油费用到达另一个城市,中间有若干加油点,起点也可加油。
解题思路:
本题是一个贪心策略题:
枚举每一个加油点i:
1、初始加油点是起点
2、汽车能跑的最大距离范围内,找到下一个更便宜的加油点的位置
3、如果能找到更便宜的加油点j,则在i点加的油只需满足能跑到j点即可
4、如果在最大距离范围内找不到更便宜的加油点
看看从i点能否直接跑到终点,如果可以在i点加的油满足能跑到终点即可
如果从i点无法跑到终点,则在i点加满油,并在最大距离范围内找价钱最便宜的加油点j
加油点i设置为j,继续枚举。。。
100分代码:
#include <bits/stdc++.h>
using namespace std;
double d1; //两个城市距离
double c; //邮箱容量(升)
double d2; //每升汽油行使距离
double p; //起点油价
int n; //加油站数量
double dist[10]; //每个加油点距离起点的距离,包括起点和终点,起点是0,终点是d1
double price[10]; //每个加油点的油价,起点是p,终点是1e9
double ans;
int main()
{
scanf("%lf%lf%lf%lf%d", &d1, &c, &d2, &p, &n);
dist[1] = 0, price[1] = p;
for(int i = 1; i <= n; i++)
{
scanf("%lf%lf", &dist[i + 1], &price[i + 1]);
}
dist[n + 2] = d1, price[n + 2] = 1e9;
double maxdist = c * d2; //maxdist表示加满油最多行使的距离
double rest = 0; //邮箱剩余油量
for(int i = 2; i <= n + 2; i++)
{
if(dist[i] - dist[i - 1] > maxdist) //如果两点之间距离超过加满油可行驶最大距离,则无解
{
cout << "No Solution";
return 0;
}
}
int i = 1; //i枚举每个加油点,从起点开始
while(i <= n + 1)
{
//在可以行使的最大距离内,找到第一个比i点便宜的加油点
bool yes = false;
int j;
for(j = i + 1; j <= n + 1 && dist[j] - dist[i] <= maxdist; j++)
{
if(price[j] < price[i])
{
yes = true;
break;
}
}
if(yes) //有找到便宜的加油点
{
ans += ((dist[j] - dist[i]) / d2 - rest) * price[i]; //在i点加油能跑到j点即可
rest = 0; //到j点后剩下的油量
}
else //没有找到便宜的加油点
{
if(dist[n + 2] - dist[i] <= maxdist) //没有更便宜的加油点,但可以跑到终点
{
ans += ((dist[n + 2] - dist[i]) / d2 - rest) * price[i]; //直接加油够跑到终点
break; //结束
}
else //不能跑到终点
{
ans += (c - rest) * price[i]; //则在i点把邮箱加满
double minp = 2e9, mini = i;
//找到i之后j之前价格最低的点
for(int k = i + 1; k < j; k++)
{
if(price[k] < minp)
{
minp = price[k];
mini = k;
}
}
j = mini; //下次从价格最低的点加油
rest = c - (dist[j] - dist[i]) / d2; //到j点后剩下的油量
}
}
i = j; //下一个加油点是j
}
printf("%.2lf", ans);
return 0;
}