题目:一条小溪上7块石头,如图所示:

分别有六只青蛙:A,B,C,D,E,F。A,B,C三只蛙想去右岸,它们只会从左向右跳;D,E,F三只蛙想去左岸,它们只会从右向左跳。青蛙每次最多跳到自己前方第2块石头上。请问最少要跳几次所有青蛙上岸。写出步骤。

这个题是个路径搜索的问题,在解空间搜索所有的解,并找出最优的解法(即步骤最少的)。
那么怎么算是一个解呢?具体而言就是最后石头上没有青蛙了。

我们先给题目建模,7块石头,其上可以是没青蛙,可以有一只往左跳的青蛙,也可以有一只往右跳的青蛙。可以把这7块石头看成一个整体,来表示一个状态。这里我们把这7块石头看成一个数组,里面只能有0,1,2三种值,这样表示,那么初始时为:

1 , 1 , 1 , 0 , 2 , 2 , 2

我们把它再表示成一个数字,来表示状态值,这个值把这个数组按三进制拼成一个数字,我们用一个辅助函数来做这件事情:

private   final   int  makeS() {
        
         int  r = 0 ;
         int  p = 1 ;
         for ( int  i = 0 ;i < 7 ;i ++ )
        {
            r += p * states[i];
            p *= 3 ;
        }
         return  r;
    }

那么题目现在变成从状态111022转换成状态0000000,所需最少的步骤.

那么状态是怎样转换的呢?
很显然。,每次青蛙跳都会触发状态的转换,我们在每个状态时搜索每种可能的转换,我们记初始状态为S(S等于三进制111022)记要求解的值为OPT(S),假如可以转换到t1,t2,...tk.
那么,显然

OPT(S)=min(1+OPT(t1),1+OPT(t2),....,1+OPT(tk));

另外,由于最终状态为0,所以OPT(0)=0,就是说已经在最终状态了,就不需要一步就可以了。
有了上面这个等式,我们可以递归求解了,但是如果单纯的递归,会导致大量的重复计算,所以这里我们用备忘录的方法,记下已经求解出来的OPT(x),放在一个数组里,由于只有7块石头,所以最多我们需要3^7=2187个状态。我们用一个2187个元素的数组,  其中第i个元素表示OPT(i),初始化每个元素用-1表示还未求解。OPT(0) 可直接初始化为0.

到此我们还有一个问题,怎么能够在算法结束的时候打印出最优的步骤呢?按照这个步骤,我们可以重建出青蛙是如何在最优的情况下过河的。为此,我们可以再用一个步骤数组,每次在采取最优步骤的时候记录下来。

整个算法如下:

package test;

import java.util.Arrays;
/**
 *
 * @author Yovn
 *
 */
public class FrogJump {
   
    private int steps[];
    private int states[];
   
   
    private static class Step
    {
        int offset=-1;
        int jump;
        int jumpTo;
    }
   
   
    private Step jumps[];
    private int initS;
    public FrogJump()
    {
        steps=new int[81*27];
        states=new int[7];
        for(int i=0;i<3;i++)states[i]=1;
        for(int i=4;i<7;i++)states[i]=2;
        Arrays.fill(steps, -1);
        steps[0]=0;
        jumps=new Step[81*27];
        initS=makeS();
    }
   
    public int shortestSteps(int s)
    {
        if(steps[s]==-1)
        {

int minStep=Integer.MAX_VALUE;
            Step oneStep=new Step();
            for(int i=0;i<7;i++)
            {
                if(states[i]==1)
                {
                    if(i>4)
                    {
                        states[i]=0;
                        minStep = recurFind(minStep,oneStep,i,7-i);
                        states[i]=1;
                    }
                    else
                    {
                        if(states[i+1]==0)
                        {
                            states[i]=0;
                            states[i+1]=1;
                            minStep = recurFind(minStep,oneStep,i,1);
                            states[i]=1;
                            states[i+1]=0;
                           
                        }
                        if(states[i+2]==0)
                        {
                            states[i]=0;
                            states[i+2]=1;
                            minStep = recurFind(minStep,oneStep,i,2);
                            states[i]=1;
                            states[i+2]=0;
                           
                        }
                    }
                }
                else if(states[i]==2)
                {
                    if(i<2)
                    {
                        states[i]=0;
                       
                        minStep = recurFind(minStep,oneStep,i,-1-i);
                        states[i]=2;
                    }
                    else
                    {
                        if(states[i-1]==0)
                        {
                            states[i]=0;
                            states[i-1]=2;
                            minStep = recurFind(minStep,oneStep,i,-1);
                            states[i]=2;
                            states[i-1]=0;
                           
                        }
                        if(states[i-2]==0)
                        {
                            states[i]=0;
                            states[i-2]=2;
                            minStep = recurFind(minStep,oneStep,i,-2);
                            states[i]=2;
                            states[i-2]=0;
                           
                        }
                    }
                }
               
            }
            steps[s]=minStep;
            jumps[s]=oneStep;
           
           
        }
        return steps[s];

}

private final int recurFind(int minStep, Step oneStep, int pos, int jump) {
        int toS=makeS();
        int r=shortestSteps(toS);
        if(r<minStep-1)
        {
            oneStep.jump=jump;
            oneStep.offset=pos;
            oneStep.jumpTo=toS;
            minStep=r+1;
        }
        return minStep;
    }

public void printPath()
    {
        int s=initS;
        int i=1;
       
        while(s!=0)
        {
           
           
            System.out.println("["+(i++)+"] Frog at #"+jumps[s].offset+" jumps #"+jumps[s].jump);
            s=jumps[s].jumpTo;
           
        }
    }
    private final int makeS() {
       
        int r=0;
        int p=1;
        for(int i=0;i<7;i++)
        {
            r+=p*states[i];
            p*=3;
        }
        return r;
    }

/**
     * @param args
     */
    public static void main(String[] args) {
        FrogJump fj=new FrogJump();
        int steps=fj.shortestSteps(fj.initS);
       
        System.out.println("use "+steps+" steps!");
        fj.printPath();

}

}

运行结果:(#1表示向右跳一步,#-2表示向左跳二步。)

use  21  steps !
[ 1 ] Frog at # 2  jumps # 1
[ 2 ] Frog at # 4  jumps # - 2
[ 3 ] Frog at # 5  jumps # - 1
[ 4 ] Frog at # 3  jumps # 2
[ 5 ] Frog at # 1  jumps # 2
[ 6 ] Frog at # 0  jumps # 1
[ 7 ] Frog at # 2  jumps # - 2
[ 8 ] Frog at # 0  jumps # - 1
[ 9 ] Frog at # 4  jumps # - 2
[ 10 ] Frog at # 2  jumps # - 2
[ 11 ] Frog at # 0  jumps # - 1
[ 12 ] Frog at # 5  jumps # 2
[ 13 ] Frog at # 3  jumps # 2
[ 14 ] Frog at # 1  jumps # 2
[ 15 ] Frog at # 5  jumps # 2
[ 16 ] Frog at # 3  jumps # 2
[ 17 ] Frog at # 5  jumps # 2
[ 18 ] Frog at # 6  jumps # - 1
[ 19 ] Frog at # 5  jumps # - 2
[ 20 ] Frog at # 3  jumps # - 2
[ 21 ] Frog at # 1  jumps # - 2

青蛙过河程序及其解析相关推荐

  1. 一个青蛙过河程序及其解析

    近日在CSDN上看到中软一道面试题,挺有意思的. 题目:一条小溪上7块石头,如图所示: 分别有六只青蛙:A,B,C,D,E,F.A,B,C三只蛙想去右岸,它们只会从左向右跳:D,E,F三只蛙想去左岸, ...

  2. 老虎过河编程java_Java编程实例:青蛙过河程序及其解析

    题目:一条小溪上7块石头,如图所示: 分别有六只青蛙:A,B,C,D,E,F.A,B,C三只蛙想去右岸,它们只会从左向右跳;D,E,F三只蛙想去左岸,它们只会从右向左跳.青蛙每次最多跳到自己前方第2块 ...

  3. 青蛙过河 猴子爬山 兔子繁殖 开宝箱2 找气球 指针函数 铺地砖

    Problem A: 青蛙过河 Description 一条小溪尺寸不大,青蛙可以从左岸跳到右岸,在左岸有一石柱L,面积只容得下一只青蛙落脚,同样右岸也有一石柱R,面积也只容得下一只青蛙落脚.有一队青 ...

  4. 算法-经典趣题-青蛙过河

    本文为joshua317原创文章,转载请注明:转载自joshua317博客 算法-经典趣题-青蛙过河 - joshua317的博客 一.问题 青蛙过河是一个非常有趣的智力游戏,其大意如下: 一条河之间 ...

  5. 青蛙过河(二分+并查集)

    青蛙过河 来回x次,也就是从起点一共2x个青蛙走一遍到终点 用一个数组记录每次送多少个青蛙由i–>j 具体看acwing解析 #include <bits/stdc++.h> #de ...

  6. C语言青蛙过河游戏超详细教程【附源码】

    今天给大家带来一个青蛙过河小游戏代码,先看看效果吧! 开始界面: 游戏界面 : 游戏中界面:  胜利界面: 死亡界面: 代码我们分了几个模块来写,这样不容易写乱,也方便后续修改 木板模块: #incl ...

  7. 编程求解机械迷城第11关中类青蛙过河的问题

    在玩机械迷城游戏的时候,第11关遇到一个类似青蛙过河的游戏http://jingyan.baidu.com/article/e73e26c014903024adb6a7a4.html,下图是三张地图的 ...

  8. [每日一题] 128. 青蛙过河(数组、记忆化搜索、递归、剪枝)

    文章目录 1. 题目来源 2. 题目说明 3. 题目解析 方法一:哈希表.记忆化搜索.递归解法 方法二:迭代解法 方法三:回溯法+贪心策略+剪枝 1. 题目来源 链接:青蛙过河 来源:LeetCode ...

  9. java聊天程序步骤解析_java网络之基于UDP的聊天程序示例解析

    基于UDP的Socket通信 UDP协议不是一种基于稳定连接的协议,是一种面向数据报包的通信协议,不需要通信双方建立稳定的连接,也没有所谓服务端和客户的概念,数据报包在传输的时候不保证一定及时到达,也 ...

最新文章

  1. 「完结」12篇文章带你逛遍主流分割网络
  2. Algorithm:树相关算法(BBT/BST/B树/R树)简介(二叉查找树、二叉查找树的插入节点、二叉查找树的删除、二叉树的遍历、平衡二叉树)C 语言实现
  3. C++动态数组(转)
  4. [转载]C#中各种计时器
  5. Scala _04Scala字符串
  6. 《剑指offer》求二叉树的最小深度(非递归法)
  7. excel填充序列_零基础、初学者必须掌握的10个Excel技巧,办公必备!
  8. python爬虫网站简单_Python爬虫之简单爬虫框架实现
  9. Hadoop学习之路(十六)Hadoop命令hadoop fs -ls详解
  10. Linux内存映射实现框架
  11. mysql query cache_MySQL Query Cache开启与否的必要性分析
  12. html旅游旅行游记攻略网页源码
  13. mysql删除某天前的数据
  14. 大陆期货11月3日钢材日评
  15. 金边富贵竹的养护方法
  16. [渝粤教育] 西南科技大学 民法学 在线考试复习资料
  17. mvp的全称_MVP英文全称是什么
  18. html datetime控件 到时分秒,日期控件:datepicker(bootstrap)支持时分秒
  19. LM2596开关电源 多路开关电源 DC-DC降压电源 固定/可调输出 原理图和PCB
  20. 自学编程难吗?如何学?

热门文章

  1. Axon 4.4 中文版文档(一)
  2. C#面向对象程序设计课程实验一:实验名称:C#语言基础、程序流程控制
  3. 基于web的在线视频编辑的设计
  4. MATLAB学习(一)——APP的学习笔记
  5. CTypedPtrArray的引用
  6. 钽电容的作用,钽电容滤波好的原因
  7. 谈谈制造企业如何制定敏捷的数字化转型策略
  8. 电脑怎么实现长截图、滚动截图?亲测三款好用软件,附图文教程
  9. 《Domain Separation Networks》文献翻译
  10. wordpress谷歌字体_适用于WordPress网站的10种性能最高的Google AdSense标语尺寸和格式