青蛙过河程序及其解析
题目:一条小溪上7块石头,如图所示:
分别有六只青蛙:A,B,C,D,E,F。A,B,C三只蛙想去右岸,它们只会从左向右跳;D,E,F三只蛙想去左岸,它们只会从右向左跳。青蛙每次最多跳到自己前方第2块石头上。请问最少要跳几次所有青蛙上岸。写出步骤。
这个题是个路径搜索的问题,在解空间搜索所有的解,并找出最优的解法(即步骤最少的)。
那么怎么算是一个解呢?具体而言就是最后石头上没有青蛙了。
我们先给题目建模,7块石头,其上可以是没青蛙,可以有一只往左跳的青蛙,也可以有一只往右跳的青蛙。可以把这7块石头看成一个整体,来表示一个状态。这里我们把这7块石头看成一个数组,里面只能有0,1,2三种值,这样表示,那么初始时为:
我们把它再表示成一个数字,来表示状态值,这个值把这个数组按三进制拼成一个数字,我们用一个辅助函数来做这件事情:
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.
那么,显然
另外,由于最终状态为0,所以OPT(0)=0,就是说已经在最终状态了,就不需要一步就可以了。
有了上面这个等式,我们可以递归求解了,但是如果单纯的递归,会导致大量的重复计算,所以这里我们用备忘录的方法,记下已经求解出来的OPT(x),放在一个数组里,由于只有7块石头,所以最多我们需要3^7=2187个状态。我们用一个2187个元素的数组, 其中第i个元素表示OPT(i),初始化每个元素用-1表示还未求解。OPT(0) 可直接初始化为0.
到此我们还有一个问题,怎么能够在算法结束的时候打印出最优的步骤呢?按照这个步骤,我们可以重建出青蛙是如何在最优的情况下过河的。为此,我们可以再用一个步骤数组,每次在采取最优步骤的时候记录下来。
整个算法如下:
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表示向左跳二步。)
[ 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
青蛙过河程序及其解析相关推荐
- 一个青蛙过河程序及其解析
近日在CSDN上看到中软一道面试题,挺有意思的. 题目:一条小溪上7块石头,如图所示: 分别有六只青蛙:A,B,C,D,E,F.A,B,C三只蛙想去右岸,它们只会从左向右跳:D,E,F三只蛙想去左岸, ...
- 老虎过河编程java_Java编程实例:青蛙过河程序及其解析
题目:一条小溪上7块石头,如图所示: 分别有六只青蛙:A,B,C,D,E,F.A,B,C三只蛙想去右岸,它们只会从左向右跳;D,E,F三只蛙想去左岸,它们只会从右向左跳.青蛙每次最多跳到自己前方第2块 ...
- 青蛙过河 猴子爬山 兔子繁殖 开宝箱2 找气球 指针函数 铺地砖
Problem A: 青蛙过河 Description 一条小溪尺寸不大,青蛙可以从左岸跳到右岸,在左岸有一石柱L,面积只容得下一只青蛙落脚,同样右岸也有一石柱R,面积也只容得下一只青蛙落脚.有一队青 ...
- 算法-经典趣题-青蛙过河
本文为joshua317原创文章,转载请注明:转载自joshua317博客 算法-经典趣题-青蛙过河 - joshua317的博客 一.问题 青蛙过河是一个非常有趣的智力游戏,其大意如下: 一条河之间 ...
- 青蛙过河(二分+并查集)
青蛙过河 来回x次,也就是从起点一共2x个青蛙走一遍到终点 用一个数组记录每次送多少个青蛙由i–>j 具体看acwing解析 #include <bits/stdc++.h> #de ...
- C语言青蛙过河游戏超详细教程【附源码】
今天给大家带来一个青蛙过河小游戏代码,先看看效果吧! 开始界面: 游戏界面 : 游戏中界面: 胜利界面: 死亡界面: 代码我们分了几个模块来写,这样不容易写乱,也方便后续修改 木板模块: #incl ...
- 编程求解机械迷城第11关中类青蛙过河的问题
在玩机械迷城游戏的时候,第11关遇到一个类似青蛙过河的游戏http://jingyan.baidu.com/article/e73e26c014903024adb6a7a4.html,下图是三张地图的 ...
- [每日一题] 128. 青蛙过河(数组、记忆化搜索、递归、剪枝)
文章目录 1. 题目来源 2. 题目说明 3. 题目解析 方法一:哈希表.记忆化搜索.递归解法 方法二:迭代解法 方法三:回溯法+贪心策略+剪枝 1. 题目来源 链接:青蛙过河 来源:LeetCode ...
- java聊天程序步骤解析_java网络之基于UDP的聊天程序示例解析
基于UDP的Socket通信 UDP协议不是一种基于稳定连接的协议,是一种面向数据报包的通信协议,不需要通信双方建立稳定的连接,也没有所谓服务端和客户的概念,数据报包在传输的时候不保证一定及时到达,也 ...
最新文章
- 「完结」12篇文章带你逛遍主流分割网络
- Algorithm:树相关算法(BBT/BST/B树/R树)简介(二叉查找树、二叉查找树的插入节点、二叉查找树的删除、二叉树的遍历、平衡二叉树)C 语言实现
- C++动态数组(转)
- [转载]C#中各种计时器
- Scala _04Scala字符串
- 《剑指offer》求二叉树的最小深度(非递归法)
- excel填充序列_零基础、初学者必须掌握的10个Excel技巧,办公必备!
- python爬虫网站简单_Python爬虫之简单爬虫框架实现
- Hadoop学习之路(十六)Hadoop命令hadoop fs -ls详解
- Linux内存映射实现框架
- mysql query cache_MySQL Query Cache开启与否的必要性分析
- html旅游旅行游记攻略网页源码
- mysql删除某天前的数据
- 大陆期货11月3日钢材日评
- 金边富贵竹的养护方法
- [渝粤教育] 西南科技大学 民法学 在线考试复习资料
- mvp的全称_MVP英文全称是什么
- html datetime控件 到时分秒,日期控件:datepicker(bootstrap)支持时分秒
- LM2596开关电源 多路开关电源 DC-DC降压电源 固定/可调输出 原理图和PCB
- 自学编程难吗?如何学?