汽车加油问题
问题描述:
一辆汽车加满油后可行驶n公里。旅途中有若干个加油站。设计一个有效算法,在哪些加油站停靠加油,使沿途加油次数最少。
对于给定的n(n <= 5000)和k(k <= 1000)个加油站位置,编程计算最少加油次数。
test.txt
7 7
1 2 3 4 5 1 6 6
output.txt
4
算法思路:
首先加油站之间的距离d必须小于汽车加满油行使的公里数,即d<n。该问题需要使得加油次数最少,所以只要行使到编号为i加油站后,剩余的油能够成功行使到编号为i+1的加油站,那么就不需要在编号为i的加油站加油。只有剩余的油量不足以行使到编号为i+1的加油站,才需要在编号为i的加油站加油,否则将无法成功到达目的地。为了计算加油次数,引入numbers变量计数;为了输出加油站的编号,引入x[k+1]数组标记加油站的编号。x[i]=0,表示未在编号i的加油站加油; x[i]=1,表示在编号为i的加油站加油。
该算法的贪心选择的意义是,使每一次加油尽可能行使到最远的距离,以此来减少加油的次数。
代码:
#include <iostream>
#include <stdio.h>
using namespace std;
void CarRefuelingGreedy(int n, int *d, int k,int *x,int &numbers){
int i,sumD = n; //sumD表示上一站剩余的油量
numbers = 0;
for(i = 1; i<=(k-1); i++){
x[i] = 0;
}
for(i = 1; i<=k; i++){
if(sumD<d[i]){ //上一站剩余的油量 小于 上一站到这一站需要的油量
x[i-1] = 1; //在上一站加油
numbers++; //加油次数加一
sumD = n-d[i]; //到这一站剩余的油量
} else{
sumD-=d[i];
}
}
}
int main(){
int n,k,numbers;
FILE *f = fopen("test.txt","r");
fscanf(f,"%d",&n);
fscanf(f,"%d",&k);
cout<<"加满油行驶的公里数:"<<n<<endl;
cout<<"加油站数:"<<k<<endl;
int *d = new int [k+2];
int *x = new int [k+1];
for(int i = 1; i<=(k+1); i++){
fscanf(f,"%d",d+i);
cout<<"加油站"<<i-1<<"加油站"<<i<<"之间的距离为:"<<d[i]<<endl;
}
CarRefuelingGreedy(n,d,k+1,x,numbers);
cout<<"加油次数:"<<numbers<<endl<<"加油点:";
for(int i = 1; i<=k; ++i){
if(x[i]) cout<<"加油站"<<i<<" ";
}
}
运行结果: