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

Posted 香菜聊游戏

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法-猴子运香蕉,看谁剩的多,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;
   

以上是关于算法-猴子运香蕉,看谁剩的多,N种解法的主要内容,如果未能解决你的问题,请参考以下文章

算法-猴子搬香蕉

java经典算法题——猴子吃桃

猴子分香蕉

华为OD机试 - 猴子爬山(Java) | 机试题+算法思路+考点+代码解析 2023

经典的猴子分香蕉问题

LQ0120 猴子分香蕉枚举