C#深度和广度优先分油问题

-、问题描述

分油问题:两个小孩去打油,一人带了一个一斤的空瓶,另一个带了一个七两和一个三两的空瓶。原计划各打一斤油,可是由于所 带的钱不够,只好合打了一斤油,在回家的路上,二人想平分这一斤油,可是又没有其它工具。现只用这三个瓶子(一斤、七两、三两)精确地分出两个半斤油来。

二、算法描述

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)广度优先算法实现图

从 以上两个结果来看,如果存在解则广度优先总能找到最优解,但是从时间上来看深度优先更快而广度优先需要遍历每个结点造成时间空间都开销比较大,所以时间上 肯定花的比较多。但是可以保证找到最优解。此问题由于比较简单,复杂度不高,只需在第九步就可以找到最优解了,因此深度优先是可取的,但是如果是在某些复 杂的问题中,此算法就可能导致组合爆炸,占用空间过大导致算法的不可行。

时间: 2024-09-30 11:35:29

C#深度和广度优先分油问题的相关文章

深度和广度优先分油问题(C#实现)

问题 分油问题 -.问题描述 分油问题:两个小孩去打油,一人带了一个一斤的空瓶,另一个带了一个七两和一个三两的空瓶.原计划各打一斤油,可是由于所带的钱不够,只好合打了一斤油,在回家的路上,二人想平分这一斤油,可是又没有其它工具.现只用这三个瓶子(一斤.七两.三两)精确地分出两个半斤油来. 二.算法描述 F 算法选择 通过分析题目并结合深度优先.广度优先和迭代加深搜索的算法的特点以及有缺点,这里选择广度优先算法来求解该分油问题.如果采用深度优先算法搜索,由于其盲目性导致搜索陷入局部陷阱,并不一定能

只有五行的Floyd最短路算法

暑假,小哼准备去一些城市旅游.有些城市之间有公路,有些城市之间则没有,如下图.为了节省经费以及方便计划旅程,小哼希望在出发之前知道任意两个城市之前的最短路程. 上图中有4个城市8条公路,公路上的数字表示这条公路的长短.请注意这些公路是单向的.我们现在需要求任意两个城市之间的最短路程,也就是求任意两个点之间的最短路径.这个问题这也被称为"多源最短路径"问题. 现在需要一个数据结构来存储图的信息,我们仍然可以用一个4*4的矩阵(二维数组e)来存储.比如1号城市到2号城市的路程为2,则设e[

多源最短路径算法---Floyd-Warshall

暑假,小哼准备去一些城市旅游.有些城市之间有公路,有些城市之间则没有,如下图.为了节省经费以及方便计划旅程,小哼希望在出发之前知道任意两个城市之前的最短路程. 上图中有4个城市8条公路,公路上的数字表示这条公路的长短.请注意这些公路是单向的.我们现在需要求任意两个城市之间的最短路程,也就是求任意两个点之间的最短路径.这个问题这也被称为"多源最短路径"问题. 现在需要一个数据结构来存储图的信息,我们仍然可以用一个4*4的矩阵(二维数组e)来存储.比如1号城市到2号城市的路程为2,则设e[

.net-怎么在chartlet中更改XUnite连接数据库并连接数据库

问题描述 怎么在chartlet中更改XUnite连接数据库并连接数据库 怎么在chartlet中更改XUnit.YUnit等属性在哪里改,我没学过C# .net还请高人指点,还有连接数据库 谢谢了 解决方案 假设图中数据元素类型是字符型,请采用邻接矩阵或邻接表实现图的以下基本操作: (1)构造图(包括有向图.有向网.无向图.无向网): (2)根据深度和广度优先遍历图. 解决方案二: 根据深度和广度优先遍历图.

遍历-求用C语言实现下面问题 新手求指点~谢谢~

问题描述 求用C语言实现下面问题 新手求指点~谢谢~ 假设图中数据元素类型是字符型,请采用邻接矩阵或邻接表实现图的以下基本操作: (1)构造图(包括有向图.有向网.无向图.无向网): (2)根据深度和广度优先遍历图. 解决方案 包括有向图.有向网.无向图.无向网,根据深度和广度优先遍历图.http://blog.csdn.net/creazyapple/article/details/7949064http://blog.csdn.net/lwwworkspace/article/details

《趣题学算法》目录—导读

版权 趣题学算法 • 著 徐子珊 责任编辑 张 涛 • 人民邮电出版社出版发行 北京市丰台区成寿寺路11号 邮编 100164 电子邮件 315@ptpress.com.cn 网址 http://www.ptpress.com.cn • 读者服务热线:(010)81055410 反盗版热线:(010)81055315 内容提要 趣题学算法 本书共分10章.第0章讲解了算法的概念及体例说明.第1-7章分别就计数问题.信息查找问题.组合优化问题.图中搜索问题和数论问题展开,讨论了算法的构思和设计,详

设计爬虫Hawk背后的故事

五年之痒 2016年,能记入个人年终总结的事情没几件,其中一个便是开源了Hawk.我花不少时间优化和推广它,得到的评价还算比较正面,因为负面评价也没什么渠道进我耳朵. 不过你知道我写这个东西花了多久吗? 掐头去尾,这是第五个年头了. 读研究生伊始,实验室开始做数据挖掘,但我发现大家做研究,都是一段段的代码,遇到新问题,就不得不再拷贝一份修改,很少想过复用.于是我便花了一年的时间,开发了一款现在看起来配色丧心病狂的"数据挖掘软件": 它居然能在上面刷微博,能把任何一个学姐学妹在微博的蛛丝

邻接图的深度广度优先遍历

邻接图的优点就是,现用现申请,空间存储很灵活,并且需要的空间也很小.我们在做复杂网络时,通常也是用这种方法.缺点是不适合并行化,因为cuda只支持连续地址空间的拷贝. 数据结构 主要包括,边节点和顶点节点 typedef struct edgeNode{ int num; int weight; struct edgeNode * next; }edgeNode; typedef struct vertexNode{ char data; edgeNode * firstNode; }verte

算法研究:图的广度优先遍历

图的遍历和树的遍历类似,我们希望从图中某一顶点出发访遍图中其余顶点,且使每一个顶点仅被访问一次,这一过程 就叫做图的遍历(Traverse Graph). 图的遍历方法一般有两种,第一种是我们在前面讲过的<深度优先遍历 (Depth First Search)>,也有称为深度优先搜索,简称为DFS.第二种是广度优先遍历(Breadth  First Search), 也有称为广度优先搜索,简称为BFS.我们在<队列与广度优先搜索>中已经较为详细地讲述了广度优先搜索的策略,这里 不再