一辆吉普车来到1000km宽的沙漠边沿。吉普车的耗油量为1L/km,总装油量为500L。显然,吉普车必须用自身油箱中的油在沙漠中设几个临时 加油点,否则是通不过沙漠的。假设在沙漠边沿有充足的汽油可供使用,那么吉普车应在哪些地方、建多大的临的加油点,才能以最少的油耗穿过这块沙漠?
从这个题目来看,这是一个极限问题,求得是最少耗油的量,所以只有唯一答案。
1、为了穿越这个沙漠,同时耗油量最少,那么吉普车就应该每次出发的时候都要满油量出发。
2、为了保证每一次都是满油量的从每个临时加油站出发,那么每一个临时加油站的油量储备都应该是500L的倍数。
3、为了保证耗油量最少,每一次建立一个临时加油站的时候,运输的次数也是越少越好,减少重复的路段。
4、如果这道题通过递推法正推的话很难确定第一个临时加油站的地点。
5、所以这里我们用倒推法来做。
6、假设我们已经到达了B点,这个时候B点的储油量应该0,这是可以倒推C1点的储油量应该为500L,这时候可以刚好到达终点B。好了现在我们知道C1点的储油量了,也就知道了C1到B点的距离为500米。
7、这时候我们应该想,如果向C1点运输500L的油量,C2点应该存储多少油呢?根据上面的步骤2(临时加油站的油量储备都应该是500L的倍数)和步骤3(运输的次数也是越少越好,这里肯定是两次或者两次以上才能向C1点运输500L油,这里取2次),那么我们就知道了C2点的储油量应该是500L*2,也就是1000L油。这时,C2到C1的距离为500/3。
8、如果想C2点运输1000L的油,重复步骤7可知,C3点存储油量为500×3L,C3到C2的距离为500/5。
9、所以到达临时加油站Cn的时候,储油量应该是500×n,Cn到Cn-1的距离为500/2n-1。
所以这里通过下面这个式子算出n:
500+500/3+500/5+500/(2n-1) = 1000;
然后就可以得出最少耗油量。
public class Desert {
public double totaldistance;//总长度
public double speed;//单位距离的油耗速度
public double oilper;//单次的最大负载
public void result(double total,double speed,double oilper) {
this.oilper=oilper;
this.speed=speed;
this.totaldistance=total;
//假设都是满载行驶
double distance = oilper/speed;//每段路的距离
if(totaldistance <= distance) {
System.out.println("总距离小于第一段距离,可以一次通过。");
}
//需要设置补给站点,每个站点的存储量为单次的最大负载的整数倍
double dis=distance;
int i=0;//站点个数
while(dis < totaldistance) {
//每一个站点的距离之和,即计算设置多少个站点才能通过totaldistance总长
i++;
dis+=1.0/(2*i+1)*distance;
}
int num=i;
double totalOil = 0;
while(i>0) {
dis-=distance/(2*i+1);
i--;
if(totalOil==0) {
totalOil=oilper*i+(totaldistance-dis)*(2*i+1)/speed;
}
System.out.println("第"+(num-i)+"个站点为距离起点"+(totaldistance-dis)+"处,存储量为"+oilper*i+"L");
}
System.out.println("总耗油量为"+totalOil+"L");
}
public static void main(String[] args) {
double total=1000.0;
double speed=1.0;
double oilper=500.0;
Desert desert=new Desert();
desert.result(total,speed,oilper);
}
}
第1个站点为距离起点22.433122433122435处,存储量为3000.0L
第2个站点为距离起点60.89466089466089处,存储量为2500.0L
第3个站点为距离起点106.34920634920638处,存储量为2000.0L
第4个站点为距离起点161.90476190476193处,存储量为1500.0L
第5个站点为距离起点233.33333333333337处,存储量为1000.0L
第6个站点为距离起点333.33333333333337处,存储量为500.0L
第7个站点为距离起点500.0处,存储量为0.0L
总耗油量为3291.630591630592L
某王国对囚犯进行大赦,让一狱吏n次通过一排锁着的n间牢房,每通过一次按所定规则转动门锁,每转动一次,原来锁着的被打开,原来打开的被锁上;通过n次后,门锁开着的,牢房中的犯人放出,否则犯人不得获释.转动门锁的规则是这样的,第一次通过牢房,要转动每一把门锁,即把全部锁打开;第二次通过牢房时,从第二间开始转动,每隔一间转动一次;第k次通过牢房,从第k间开始转动,每隔k-1 间转动一次;问通过n次后,哪些牢房的锁仍然是打开的?
牢房可以视作一个一元数组,1代表锁着,0代表开锁。
规律:当锁的标号为一个数的平方时,那么最后它会开着。
public class Warder {
public void WarderResult(int n) {
//1表示锁着,0表示开锁
System.out.println("暴力法");
int room[] = new int[n];
int i;
for (i=0;i<n;i++) {
//初始状态都是锁着
room[i]=1;
}
System.out.println("牢房数为"+n+"时");
int k,j;
for(i=1;i<=n;i++) {
//i表示通过牢房次数
System.out.print("第"+i+"次通过牢房");
for(k=i;k<=n;k+=i) {
if(room[k-1]==1) {
room[k-1]=0;
}else {
room[k-1]=1;
}
}
for(j=0;j<n;j++) {
if(room[j]==0) {
System.out.print(j+1+"、");
}
}
System.out.println("是开锁的");
}
}
public void LawWarder(int n) {
System.out.println("规律法");
System.out.println("牢房数为"+n+"时");
for(int i=1;i<+n;i++)
{
if(i*i<=n) {
System.out.print(i*i+"、");
}
}
System.out.println("是开锁的");
}
public static void main(String[] args) {
int n=10;//牢房间数
Warder warder= new Warder();
warder.WarderResult(n);
warder.LawWarder(n);
}
}
暴力法
牢房数为10时
第1次通过牢房1、2、3、4、5、6、7、8、9、10、是开锁的
第2次通过牢房1、3、5、7、9、是开锁的
第3次通过牢房1、5、6、7、是开锁的
第4次通过牢房1、4、5、6、7、8、是开锁的
第5次通过牢房1、4、6、7、8、10、是开锁的
第6次通过牢房1、4、7、8、10、是开锁的
第7次通过牢房1、4、8、10、是开锁的
第8次通过牢房1、4、10、是开锁的
第9次通过牢房1、4、9、10、是开锁的
第10次通过牢房1、4、9、是开锁的
规律法
牢房数为10时
1、4、9、是开锁的