算法-猴子运香蕉,看谁剩的多,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种解法的主要内容,如果未能解决你的问题,请参考以下文章