分油问题
-、问题描述
分油问题:两个小孩去打油,一人带了一个一斤的空瓶,另一个带了一个七两和一个三两的空瓶。原计划各打一斤油,可是由于所带的钱不够,只好合打了一斤油,在回家的路上,二人想平分这一斤油,可是又没有其它工具。现只用这三个瓶子(一斤、七两、三两)精确地分出两个半斤油来。
二、算法描述
F 算法选择
通过分析题目并结合深度优先、广度优先和迭代加深搜索的算法的特点以及有缺点,这里选择广度优先算法来求解该分油问题。如果采用深度优先算法搜索,由于其盲目性导致搜索陷入局部陷阱,并不一定能求得解即使得到解也不一定是最优解,因此并不采用此算法。迭代加深搜索则是在固定的深度上进行深度和广度搜索结合的策略来进行搜索,这样避免了单一的深度搜索无法得到解的缺点,但是找到的解并不一定是最优解。广度优先以牺牲空间代价和时间代价来换取保证取得最优解。由于该问题并不复杂,即使使用广度优先算法也不会占有太多的空间和时间,因此为了取得最优解这里选择广度优先算法来求解。
F 算法描述
1. 用unVisitedBttsArr表示初始节点列表(待扩展,此为一个动态数组)
2. 如果unVisitedBttsArr为空集,则退出并给出失败信号
3. n取为unVisitedBttsArr的第一个节点,并在 unVisitedBttsArr中删除节点n,放入已访问节点列表haveVisitedBttsArr
4. 如果n为目标节点,则退出并给出成功信号
5. 否则,将n的子节点加到N的末尾,并返回2)步
F 问题分析
l 选择合适的数据结构表示问题状态
F 用向量(T,S,R)表示状态——T表示10两瓶中的油量,S表示7两瓶中的油量,R表示3两瓶中的油量。
F 问题的起始状态:(10,0,0)。
F 问题的目标状态:(5,2,3)或者(5,3,2)或者(5,5,0)。
l 确定智能算子,用以表示变化状态的规则。由于总共油量为10两,而10两的瓶可以装满所有的油,因此可以把10两的瓶当作一个大油桶,这样此题就化为和上一题8/6类似的问题了。因此在描述变化状态的时候只需给出7、3瓶的状态即可,10瓶的状态即为10-S-R的油量。可是由于在程序处理上的一致性,在程序的实现上我还是把10、8、6的瓶子统一处理,而不是用两个状态表示。
号
规则
解释
1
(S,R) and S<7 à (7,R)
7斤瓶不满时装满
2
(S,R) and R <3 à (S,3)
3斤瓶不满时装满
3
(S,R) and S >0 à (0,R)
7斤瓶不空时倒空
4
(S,R) and R >0 à (S,0)
3斤瓶不空时倒空
5
(S,R) and S>0 and S+R≤3à (0,S+R)
7斤瓶中油全倒入3斤瓶
6
(S,R) and R >0 and S+R≤7à (S+R,0)
3斤瓶中油全倒入7斤瓶
7
(S,R) and S<7 and S+R≥7à (7, S+R -7)
用3斤瓶油装满7斤瓶子
8
(S,R) and R <3 and S+R≥3à (S+R -3,3)
用7斤瓶油装满3斤瓶子
三、程序设计
算法使用C#语言来实现的。程序主要根据上面提供的广度优先算法的描述来对算法进行实现的。程序共有四个类:
Bottle类,用来描述瓶子的状态以及一些行为动作和属性。
WidthSearch类,是广度优先搜索算法的实现类
DepthSearch类,是深度优先搜索算法的实现类
MainForm类,是界面设计的类。
这里提供两个算法的实现主要是为了做个对比。
以下主要对几个核心算法的程序实现进行说明介绍。
//瓶子类
public class Bottle
{
int Capability = 0 ;//瓶子的总容量
int Current = 0 ;//当前瓶子中的油量
int Remain = 0 ;//瓶子中剩余的量
//倒入油的行为动作
public void Add(int val)
{
Current += val;
Remain -= val;
}
//倒出油的行为动作
public void Sub(int val)
{
Current -= val;
Remain += val;
}
//深度优先算法实现类
public class DepthSearch
public void Searching()
{
Random r = new Random();
while(bottle_10.CurrentVal != 5) //判断是否达到目标状态
{
int random = r.Next(1,7);//用随机产生的数来随机确定下一个子状态
switch(random)
{
case 1 :
FlowTo(bottle_03,bottle_07);
break;
case 2 :
FlowTo(bottle_10,bottle_03);
break;
case 3 :
FlowTo(bottle_07,bottle_03);
break;
case 4 :
FlowTo(bottle_10,bottle_07);
break;
case 5 :
FlowTo(bottle_03,bottle_10);
break;
case 6 :
FlowTo(bottle_07,bottle_10);
break;
default :
break;
}
if(!stateArr.Contains(BottlesState()))
{
stateArr.Add(BottlesState());
}
else
{
ReturnToPreState();
}
}
}
//倒油的动作。这里是从bottle1倒到bottle2
private void FlowTo(Bottle bottle1,Bottle bottle2)
{
if(bottle1.CurrentVal>bottle2.RemainVal)
{
bottle1.Sub(bottle2.RemainVal);
bottle2.CurrentVal = bottle2.CapabilityVal;
}
else
{
bottle2.Add(bottle1.CurrentVal);
bottle1.CurrentVal = 0;
}
}
//广度优先搜索实现类
public class WidthSearch
public void S(TreeNode node)
{
while(unVisitedBttsArr.Count>=0) //未访问表中如果有结点继续循环搜索否则跳出
{
TreeNode n = (TreeNode)unVisitedBttsArr[0];
bool flag = true;
//检查是否已经访问过
foreach(TreeNode i in haveVisitedBttsArr)
{
if(i.Text.Equals(n.Text))
{
haveVisitedBttsArr.Add(unVisitedBttsArr[0]);
unVisitedBttsArr.RemoveAt(0);
flag = false;
break;
}
}
//若已经遍历过的不需要继续遍历 跳到下一个
if(flag)
{
if(Search(n))
{
return;
}
}
}
}
//创建子结点并加入到unVisitedBttsArr中。
private bool CreateNode(TreeNode node)
{
TreeNode n = new TreeNode(BottlesState());
unVisitedBttsArr.Add(n);
if(bottle_10.CurrentVal == 5)
{
node.Nodes.Add(n);
SetPath(n);
return true;
}
node.Nodes.Add(n);
return false;
}
//回溯取得最佳路径
private void SetPath(TreeNode n)
{
while(n.Parent!=null)
{
path = n.Text + " -> " + path;
n.ForeColor = System.Drawing.Color.Blue;
n = n.Parent;
}
}
四、试验结果
如下是试验结果:
1)深度优先随机产生子结点的搜索路径
2)广度优先算法实现图
从以上两个结果来看,如果存在解则广度优先总能找到最优解,但是从时间上来看深度优先更快而广度优先需要遍历每个结点造成时间空间都开销比较大,所以时间上肯定花的比较多。但是可以保证找到最优解。此问题由于比较简单,复杂度不高,只需在第九步就可以找到最优解了,因此深度优先是可取的,但是如果是在某些复杂的问题中,此算法就可能导致组合爆炸,占用空间过大导致算法的不可行。
分享到:
相关推荐
在这个项目中,我们将使用两种主要的搜索策略——广度优先遍历(BFS)和深度优先遍历(DFS)来解决这个问题。这两种方法都是在图或树结构中寻找路径的有效手段,尤其是在解决迷宫问题、路径规划和状态空间探索等问题...
八数码问题的解决通常涉及两种主要的搜索算法:深度优先搜索(DFS)和广度优先搜索(BFS)。 深度优先搜索是一种递归的搜索策略,它尽可能深地探索树的分支。在八数码问题中,DFS会从当前状态出发,尝试所有可能的...
广度优先搜索(BFS)和深度优先搜索(DFS)是解决此类问题的两种常用算法。 **广度优先搜索(BFS)**是一种图形搜索算法,其核心思想是从起始节点开始,逐步探索所有可能的路径,优先考虑较短的路径。在八数码问题...
总之,理解和掌握树的非递归层次遍历和广度优先遍历是提高C#编程能力的关键一步,尤其是在处理复杂数据结构和算法问题时。队列和栈作为基础数据结构,其灵活运用能够解决许多实际问题,为程序设计提供强大支持。
**广度优先搜索(BFS)**是一种在图或树数据结构中遍历节点的算法,它从根节点开始,并逐层地访问所有相邻节点,然后再扩展到下一层。在C#中,实现BFS通常涉及到队列数据结构,因为BFS按照层次顺序访问节点。 **1. ...
本文将详细探讨C#中实现迷宫的深度优先搜索(DFS)和宽度优先搜索(BFS)的方法,以及如何找出从起点到终点的最短路径。 深度优先搜索(DFS)是一种用于遍历或搜索树或图的算法,它尽可能深地探索树的分支。在迷宫...
接下来是广度优先排序(Breadth-First Search,BFS)。与DFS不同,BFS从根节点开始,逐层地访问节点,先访问所有相邻节点,再访问这些相邻节点的相邻节点,直到所有节点都被访问。BFS通常用于找出图中两个节点间的...
本教程将重点讨论如何使用C#语言,结合广度优先搜索(Breadth First Search, BFS)和深度优先搜索(Depth First Search, DFS)来实现贪吃蛇的自动寻路功能。这两种算法是图论和计算机科学中的基础搜索策略,它们在...
八数码问题,用广度优先和深度优先算法实现。并且用mfc实现界面,让结果算法运行过程以动画显示。并附上实验报告.zip
总之,这个C#实现的迷宫路径搜索项目不仅展示了广度优先搜索的原理,还融入了图形化交互设计,使得学习和应用算法变得更加直观和有趣。对于想要提升算法能力或者对游戏编程感兴趣的开发者来说,这是一个极具价值的...
在计算机科学领域,解决这类问题通常运用图搜索算法,如深度优先搜索(DFS)、广度优先搜索(BFS)以及启发式搜索算法A*。 深度优先搜索(DFS)是一种用于遍历或搜索树或图的算法。在八数码问题中,DFS会尽可能深地...
在迷宫寻径问题中,A*算法通常优于深度优先和广度优先搜索,因为它能够找到更短的路径。 深度优先搜索(DFS)是一种递归的搜索策略,它尽可能深地探索树的分支。在迷宫中,DFS会一直向前走,直到无路可走才回溯。...
在IT领域,迷宫问题是一个经典的算法挑战,它通常用于教授和练习搜索算法,如深度优先搜索(DFS)和广度优先搜索(BFS)。在这个案例中,我们关注的是一个用C#编程语言实现的迷宫问题解决方案,该方案特别采用了广度...
这个问题可以通过状态空间搜索算法(如深度优先搜索或广度优先搜索)来解决,或者用动态规划来找到最优解。 描述中提到的“窗口动态演示过河过程”意味着开发者不仅实现了算法,还创建了一个用户界面,能够可视化地...
在本压缩包中,包含了一系列与数据结构及其应用相关的主题:广度优先搜索(BFS)、深度优先搜索(DFS)、拓扑排序、最短路径算法以及最小生成树。这些知识点都是解决复杂问题和优化算法设计的基础。 首先,让我们...
这涉及到深度优先搜索(DFS)、广度优先搜索(BFS)或者启发式搜索策略,如A*算法,以优化查找效率。 5. **多线程与并发**:为了保证游戏流畅运行,可能需要在后台线程处理某些计算密集型任务,例如检查匹配和消除...
8数码问题的解决方案通常采用搜索算法,如深度优先搜索(DFS)或广度优先搜索(BFS)。 在本解决方案中,开发者选择了双向广度优先搜索作为核心算法。BFS是一种用于遍历或搜索树或图的算法,其特点是从起始节点开始...
在这个实现中,问题被用C#编程语言解决,不涉及A*算法,而是采用了两种常见的搜索策略:深度优先搜索(DFS)和广度优先搜索(BFS)。 深度优先搜索是一种递归的搜索方法,它尽可能深地探索树的分支。在八数码问题中...
本书会详细讲解排序算法(如冒泡排序、选择排序、插入排序、快速排序、归并排序、堆排序等)、查找算法(如线性查找、二分查找、哈希查找)、图算法(如深度优先搜索、广度优先搜索、最短路径算法)以及动态规划等...