算法-猴子运香蕉,看谁剩的多,N种解法

 一个猴子身带100个香蕉,他距离家50米。这个猴子要带香蕉回去,但是他一次最多只能背50个香蕉,而且,每走一米他就要吃掉一个香蕉(往 回走也要吃香蕉)。这个猴子最后最多可以带多少个香蕉到家??

第一种解法

package monkey
 
import "fmt"
 
var bagSize_ int
var roadLength_ int
var totalBanana_ int
var costPerStep_ int
 
func Play(roadLength int, bagSize int, totalBanana int, costPerStep int){
   bagSize_ = bagSize
   roadLength_ = roadLength
   totalBanana_ = totalBanana
   costPerStep_ = costPerStep
 
   //初始化道路
   road = make([]int, roadLength + 1)
   road[0] = totalBanana
 
   monkey_ := monkey{}
 
   defer func() {
      if err := recover(); err != nil {
         fmt.Println(err)
         fmt.Println(monkey_)
         fmt.Println(road)
      }
   }()
 
   move(&monkey_)
 
   fmt.Println("road info: ", road)
   fmt.Println("banan at home: ", road[roadLength])
}
 
func move(monkey *monkey){
   monkey.release()
   fmt.Println("road map >>> ", road)
    
   if monkey.shouldBack() {
      monkey.back()
   } else {
      if(monkey.position == roadLength_){
         //猴子到家
         return
      }
      monkey.pickUp()
      monkey.forward()
   }
   move(monkey)
}
 
var road []int
 
type monkey struct {
   position int
   bag int
}
 
//拾起
func (monkey *monkey) pickUp() {
   here := road[monkey.position]
   if here <= 0 {
      return
   }
   pickUpCount := here - monkey.bag
   if (pickUpCount + monkey.bag) > bagSize_ {
      pickUpCount = bagSize_ - monkey.bag
   }
   //填充猴子背包
   monkey.bag = monkey.bag + pickUpCount
   //扣减路上的香蕉
   road[monkey.position] = here - pickUpCount
}
 
//放下香蕉
func (monkey *monkey) release(){
   road[monkey.position] = road[monkey.position] + monkey.bag
   monkey.bag = 0
}
 
 
//前进
func (monkey *monkey) forward(){
   cost := 1*costPerStep_
   monkey.bag = monkey.bag - cost
   monkey.position = monkey.position + cost
   if monkey.bag < 0 {
      panic("no enough banana to home, die ...")
   }
}
 
//后退
func (monkey *monkey) back()  {
   cost := 1*costPerStep_
   //退回之前如果背包里没有香蕉,先补充一个
   if monkey.bag < cost {
      monkey.bag = cost
      road[monkey.position] = road[monkey.position] - cost
   }
   monkey.bag = monkey.bag - cost
   monkey.position = monkey.position - cost
}
 
//应该后退吗
func (monkey *monkey) shouldBack() bool {
   //前面还有多少
   if monkey.position == 0 {
      return false
   }
   left := road[monkey.position - 1]
   //最多可以拾起数量
   var canPick int
   if left >= bagSize_ {
      canPick = bagSize_
   } else {
      canPick = left
   }
   //退一步拾起,耗费两个香蕉
   profits := canPick - 2*costPerStep_
   return profits > 0
}

第二种解法

public class Mb {
   public static void main(String... arg) {
      recursiveMove(100, 50, 50, 1);
      move(100, 50, 50, 1);
      //recursiveMove(3000, 1000, 1000, 1);
   }
 
   /**
    * 循环算法
    * @param total 总数量
    * @param capacity 每次最多搬多少个
    * @param distance 距离
    * @param eatNum 每走一米吃的数量
    * @return 到家剩余的数量
    **/
   public static void move(int total, int capacity, int distance, int eatNum) {
 
      // 已经搬到的位置, 即搬了几米
      int location = 0;
 
      // 每次搬运起始点剩的数量
      int currentStartNum = total;
 
      // 每次搬运终点剩的数量
      int currentEndNum = 0;
 
      // 所有剩余香蕉移动一个位置
      while (location < distance && currentStartNum > eatNum) {
         System.out.println("当前所在位置" + location + "剩下" + currentStartNum + "个香蕉");
 
         // 每筐香蕉移动一个位置, 是移动一个位置的具体细节
         // 如果搬运起点还剩2个,返回去已经没有意义
         while (currentStartNum > eatNum * 2) {
 
            if (currentStartNum > capacity) {
               moveOnePosition(location, location + 1, capacity, eatNum);
               currentStartNum -= capacity;
               currentEndNum += capacity - eatNum;
            } else {
               moveOnePosition(location, location + 1, currentStartNum, eatNum);
               // 直接向前走
               currentEndNum += currentStartNum - eatNum;
               currentStartNum = 0;
            }
 
            // 需不需要搬起点剩下的, 即需不需要返回
            if (currentStartNum > eatNum * 2) {
               moveOnePosition(location + 1, location, -1, eatNum);
               currentEndNum -= eatNum;
            }
         }
 
         currentStartNum = currentEndNum;
         currentEndNum = 0;
         location++;
      }
 
      if (location < distance) {
         System.out.println("---猴子爬不到终点,饿死了---");
      } else {
         System.out.println("成功走到终点, 剩余" + currentStartNum + "个");
      }
   }
 
   /**
    * 递归算法
    * @param total 总数量
    * @param capacity 每次最多搬多少个
    * @param distance 距离
    * @param eatNum 每走一米吃的数量
    * @return 到家剩余的数量
    **/
   public static void recursiveMove(Integer total, Integer capacity, Integer distance, Integer eatNum) {
 
      // 已经搬到的位置
      Integer location = 0;
 
      // 每次搬运起始点剩的数量
      Integer currentStartNum = total;
 
      // 每次搬运终点剩的数量
      Integer currentEndNum = 0;
 
      stepMove(location, distance, capacity, currentStartNum, currentEndNum, eatNum);
   }
 
   private static void stepMove(int location, int distance, int capacity, int currentStartNum, int currentEndNum, int eatNum) {
      if (location < distance && currentStartNum > eatNum) {
         // 所有剩余香蕉移动一个位置
         System.out.println("当前所在位置" + location + "剩下" + currentStartNum + "个香蕉");
 
         // 每筐香蕉移动一个位置, 是移动一个位置的具体细节
         // 如果搬运起点还剩2个,返回去已经没有意义
         currentEndNum = miniStep(location, distance, capacity, currentStartNum, currentEndNum, eatNum);
 
         // 向前挪一步
         currentStartNum = currentEndNum;
         currentEndNum = 0;
         location++;
 
         stepMove(location, distance, capacity, currentStartNum, currentEndNum, eatNum);
      } else {
         if (location < distance) {
            System.out.println("---猴子爬不到终点,饿死了---");
         } else {
            System.out.println("成功走到终点, 剩余" + currentStartNum + "个");
         }
      }
   }
 
   private static int miniStep(int location, int distance, int capacity, int currentStartNum, int currentEndNum, int eatNum) {
      if (currentStartNum > eatNum * 2) {
 
         if (currentStartNum > capacity) {
            moveOnePosition(location, location + 1, capacity, eatNum);
            currentStartNum -= capacity;
            currentEndNum += capacity - eatNum;
         } else {
            moveOnePosition(location, location + 1, currentStartNum, eatNum);
            // 直接向前走
            currentEndNum += currentStartNum - eatNum;
            currentStartNum = 0;
         }
 
         // 需不需要搬起点剩下的, 即需不需要返回
         if (currentStartNum > eatNum * 2) {
            moveOnePosition(location + 1, location, -1, eatNum);
            currentEndNum -= eatNum;
         }
 
         return miniStep(location, distance, capacity, currentStartNum, currentEndNum, eatNum);
      } else {
         return currentEndNum;
      }
   }
 
   /**
    * @param from 起始位置
    * @param to 目标位置
    * @param count 搬的数量
    * @param eatNum 搬一米吃的数量
    */
   private static void moveOnePosition(int from, int to, int count, int eatNum) {
      if (count != -1) {
         System.out.println("从位置" + from + "搬" + count + "个到位置" + to + ", 吃掉" + eatNum + "个");
      } else {
         System.out.println("从位置" + from + "返回到位置" + to + ", 吃掉 " + eatNum + "个");
      }
   }
 
}

第三种解法

public class recursion {
 private static Monkey monkey = new Monkey();
 // 需要搬运的香蕉
 static final int TOTAL_BANANA = 3000;
 // 路途漫漫
 static final int DISTANCE = 1000;
 // 猴子能搬运的容量
 private static final int POWER = 1000;
 // 小笔记本
 static LinkedList<Integer[]> NOTE = new LinkedList();
 public static void main(String args[]) {
  int remainBanana = getBanana(TOTAL_BANANA, 0, 0.00F);
  System.out.println("运输路线如下");
  for (Integer integ[] : NOTE) {
   System.out.printf("%d 米可用 %d 个香蕉,丢弃 %d 个香蕉", integ[0], integ[1], integ[2]);
   System.out.print("========");
  }
  System.out.printf("最后剩下了:%d 个香蕉", remainBanana);
  System.out.println();
 }
 static int getBanana(int bananaNum, int position, float rate) {
  // 香蕉数不够到达目的地
  if (bananaNum < DISTANCE) {
   Integer recode[] = {position, bananaNum};
   NOTE.add(recode);
   return -1;
  }
  int remainingBanana = bananaNum % POWER;
  int copies = bananaNum / POWER + (remainingBanana > 0 ? 1 : 0);
  int carryTimes;
  // 计算需要来回几次 carryTimes
  if (remainingBanana == 0 || remainingBanana > 2) {
   carryTimes = copies * 2 - 1;
  } else {
   carryTimes = (copies - 1) * 2 - 1;
   bananaNum = bananaNum - remainingBanana;
  }
  // 可以一次运送过去
  if ((POWER > DISTANCE - position) && carryTimes == 1) {
   Integer recode[] = {position, bananaNum, remainingBanana};
   NOTE.add(recode);
   return bananaNum - (DISTANCE - position);
  }
  int nextBananaNum = bananaNum - carryTimes;
  // 计算斜率,每单位消耗的香蕉数
  float nextRate = 1F / (bananaNum - nextBananaNum);
  if (nextRate > rate) {
   Integer recode[] = {position, bananaNum, remainingBanana};
   NOTE.add(recode);
  }
  return getBanana(nextBananaNum, position + 1, nextRate);
 }
}

第四种解法

public class Test {
 
   // 总数
   private static int total = 100;
   // 单次运送最大数
   private static int max = 50;
   // 总距离
   private static int length = 50;
   // 每次消耗
   private static int per = 1;
   // 最大值
   private static int mod = -1;
 
   public static void main(String[] args) {
      if (length * per > max || length * per > total) {
         System.out.println("无法完成");
         return;
      }
      count(length, total);
      System.out.println(mod);
   }
 
   private static void count(int length, int total) {
      // 最后多次完成
      if (length == 0) {
         if (total > mod) {
            mod = total;
         }
         return;
      }
      // 最后一次完成
      if (max > total && max > length * per) {
         if ((total - length * per) > mod) {
            mod = total - length * per;
         }
         return;
      }
 
      // i单次到达距离
      for (int i = length; i > 0; i--) {
         if (total - i * per > 0 && 2 * per * i > max) {
            continue;
         }
 
         int times;
         if (total % max == 0) {
            times = (total / max - 1) * 2 + 1;
         } else {
            if (total % max > 2 * per * i) {
               times = (total / max) * 2 + 1;
            } else {
               // 最后一次剩余不够消耗则丢弃
               times = (total / max - 1) * 2 + 1;
               total = total - total % max;
            }
         }
         int mod = total - times * i * per;
         if (mod < (length - i) * per) {
            return;
         }
 
         count(length - i, mod);
      }
   }
}

第五种解法

## 无路径版本
 
 
``` java
public class MonkeyMoveBanana2 {
 
   public static void main(String[] args) {
      int lastLeave = move(1000, 50, 50, 2);
      System.out.println("最后剩余:" + lastLeave);
   }
 
   /**
    * @param num 香蕉总数
    * @param length 距离
    * @param max 最大搬运量
    * @param per 每米消耗数
    */
   static int move(int num, int length, int max, int per) {
 
      for (int i = 0; i < length; i++) {
 
         if (num < length - i) {
            num = -1;
            break;
         }
         if (num <= max) {
            num = num - (length - i);
            break;
         }
         int n = num / max;
         int lastNum = num % max;
         if (lastNum > 2 * per) {
            n = num / max + 1;
         } else {
            num -= lastNum;
         }
         num -= (per + (n - 1) * 2 * per);
      }
 
      if (num < 0) {
         num = -1;
      }
 
      return num;
   }
}
```
 
 
## 有路径信息版本
``` java
 
public class MonkeyMoveBanana3 {
 
   public static void main(String[] args) {
      int lastLeave = move(1000, 50, 50, 1);
      if (lastLeave >= 0) {
         System.out.println("最后剩余:" + lastLeave);
      }
   }
 
   static Map<Integer, Integer> numInPos = new LinkedHashMap<>();
 
   /**
    * @param num 香蕉总数
    * @param length 距离
    * @param max 最大搬运量
    * @param per 每米消耗数
    */
   static int move(int num, int length, int max, int per) {
 
      numInPos.put(0, num);
 
      for (int i = 0; i < length; i++) {
 
         if (num < length - i) {
            num = -1;
            break;
         }
         if (num <= max) {
            go(i, length - i, per, num);
            num = num - (length - i);
            break;
         }
         int n = num / max;
         int lastNum = num % max;
         if (lastNum > 2 * per) {
            n = num / max + 1;
         } else {
            num -= lastNum;
            lastNum = 0;
         }
         num -= (per + (n - 1) * 2 * per);
 
         goMetre(i, per, max, n, lastNum);
      }
 
      if (num < 0) {
         num = -1;
         System.out.println("monkey die");
      }
 
      return num;
   }
 
 
   static void goMetre(int pos, int per, int max, int n, int lastMove) {
      for (int i = 0; i < n - 1; i++) {
         go(pos, 1, per, max);
         back(pos + 1, 1, per, 1);
      }
      if (lastMove == 0) {
         go(pos, 1, per, max);
      } else {
         go(pos, 1, per, lastMove);
      }
   }
 
   /**
    * 向前走
    *
    * @param pos 起点
    * @param distance 前进距离
    * @param per 每米消耗
    * @param payload 起点携带数量
    */
   static void go(int pos, int distance, int per, int payload) {
      int newPos = pos + distance;
      int cost = distance * per;
      int surplus = payload - cost;
 
      for (int i = 0; i < pos; i++) {
         System.out.print(" ");
      }
      for (int i = 0; i < distance; i++) {
         System.out.print(">");
      }
 
      if (!numInPos.containsKey(newPos)) {
         numInPos.put(newPos, 0);
      }
      numInPos.put(pos, numInPos.get(pos) - payload);
      numInPos.put(newPos, numInPos.get(newPos) + surplus);
 
      System.out.format("\t [%d->%d] 带%d个,进%d米,吃%d个,剩%d个。\t", pos, newPos, payload, distance, cost, surplus);
      printNumInPos();
   }
 
   /**
    * 往回走
    *
    * @param pos 起点
    * @param distance 前进距离
    * @param per 每米消耗
    * @param payload 起点携带数量
    */
   static void back(int pos, int distance, int per, int payload) {
      int newPos = pos - distance;
      int cost = distance * per;
      int surplus = payload - cost;
 
      for (int i = 0; i < newPos; i++) {
         System.out.print(" ");
      }
      for (int i = 0; i < distance; i++) {
         System.out.print("<");
      }
      numInPos.put(pos, numInPos.get(pos) - payload);
      numInPos.put(newPos, numInPos.get(newPos) + surplus);
 
      System.out.format("\t [%d<-%d] 带%d个,退%d米,吃%d个,剩%d个。\t", newPos, pos, payload, distance, cost, surplus);
      printNumInPos();
   }
 
   static void printNumInPos() {
      for (Integer key : numInPos.keySet()) {
         if (numInPos.get(key) != 0) {
            System.out.format("pos[%d]=%d\t", key, numInPos.get(key));
         }
      }
      System.out.println();
   }
 
}
```

第六种

第一种:
package com.example.sbpracdemo.houzi;
 
 
public class Test3 {
 
   public static void main(String[] args) {
      int bananaNum = 100;//香蕉总数量 150
      int carryBanana = 50;//能运多少香蕉
      int distance = 50; //距离家多远1
 
      int remainingTotalAmount = bananaNum;//剩余香蕉总数量
      //搬不走的香蕉数量
      int notCarryBanana = bananaNum - carryBanana;
      //搬走香蕉的剩余数量
      int remainingCarryBanana = carryBanana;
      //搬走香蕉
      int carryNum = carryBanana;
 
      for (int i = 1; i <= distance; i++) {
         System.out.print("走" + i + "米,搬走香蕉" + carryNum);
         remainingCarryBanana--;//走一米要吃掉一个香蕉
         remainingTotalAmount = remainingCarryBanana + notCarryBanana;
         System.out.println(",搬走香蕉的剩余数量:" + remainingCarryBanana + ",搬不走的香蕉数量:" + notCarryBanana + ",剩余香蕉总数量:" + remainingTotalAmount);
 
         //如果剩余数量小于等于能拖的数量,直接回家
         if(remainingTotalAmount<=carryBanana){
            carryNum = remainingCarryBanana;
            notCarryBanana = 0;
            continue;
         }
         //香蕉剩余数量要能够走回家
         if(remainingTotalAmount>(distance-i)){
            int temp = (int) Math.ceil((double) notCarryBanana / (double) carryBanana);
            if (temp > 1) {
               int ss=notCarryBanana;
               for (int j = 0; j < temp; j++) {
                  carryNum = carryBanana;
                  if(j==temp-1){
                     carryNum=ss-carryBanana*(temp-1);
                  }
                  //回去要吃掉一个香蕉
                  remainingCarryBanana--;
                  //背在原地的香蕉
                  notCarryBanana--; //49
                  remainingTotalAmount = remainingCarryBanana + notCarryBanana;
 
                  if (remainingTotalAmount > carryBanana) {
                     notCarryBanana = remainingTotalAmount - carryBanana;
                     remainingCarryBanana = remainingTotalAmount - notCarryBanana;
                  } else {
                     remainingCarryBanana = remainingTotalAmount;
                     notCarryBanana = 0;
                  }
                  System.out.println("回走,搬走香蕉" + carryNum + ",剩余香蕉总数量:" + remainingTotalAmount);
               }
            } else {
               if (notCarryBanana != 0) {
                  carryNum = notCarryBanana;
                  remainingCarryBanana--;//回去要吃掉一个香蕉 48
                  //背在原地的香蕉
                  notCarryBanana--; //49
                  remainingTotalAmount = remainingCarryBanana + notCarryBanana;
 
                  if (remainingTotalAmount > carryBanana) {
                     notCarryBanana = remainingTotalAmount - carryBanana;
                     remainingCarryBanana = remainingTotalAmount - notCarryBanana;
                  } else {
                     remainingCarryBanana = remainingTotalAmount;
                     notCarryBanana = 0;
                  }
                  System.out.println("回走,搬走香蕉" + carryNum + ",剩余香蕉总数量:" + remainingTotalAmount);
               }
            }
         }
         carryNum = remainingCarryBanana;
      }
      System.out.println("猴子最后最多可以带" + remainingTotalAmount + "个香蕉到家");
   }
}
 
 
 
第二种
package com.example.sbpracdemo.houzi;
 
/**
 * 密级别:classify:p2#- User: Jinlili Date: 2018/8/2322:46 Description:
 */
public class Test2 {
 
   public static void main(String[] args) {
      System.out.println(walk(100, 50, 50));
   }
 
   /**
    * @param bananaNum 总共多少根
    * @param carryBanana 每次拖多少根
    * @param distance 离家多少米
    */
   public static int walk(int bananaNum, int carryBanana, int distance) {
      int[] gj = new int[distance + 1];
      for (int i = 1; i <= distance; i++) {
         gj[i] = bananaNum;
         bananaNum = bananaNum - ((int) Math.ceil((double) bananaNum / (double) carryBanana) * 2 - 1);
         if (bananaNum < 0) {
            bananaNum = 0;
            System.out.println("不可达");
            break;
         }
      }
      return bananaNum;
   }
}

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

香菜+

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

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

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

打赏作者

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

抵扣说明:

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

余额充值