本文已参与「新人创作礼」活动,一起开启掘金创作之路。
2、量水问题描述
对量水问题给出产生式系统描述,并画出状态空间图。有两个无刻度标志的水壶,分别可装5升和2升的水。设另有一水缸,可用来向水壶灌水或倒出水,两个水壶之间,水也可以相互倾灌。已知5升壶为满壶,2升壶为空壶,问如何通过倒水或灌水操作,使能在2升的壶中量出一升的水来。
基本要求:
要求:写出算法的设计思想和源程序,并以图形用户界面实现人机交互,进行输入和输出结果,如:Please input L1: 5 Please input L2: 2
Successed or Failed?: Successed
Optimal Procedure: 50->32->30->12->10->01
方法一:求最优求解方案
状态图表示:
图虽简陋内容不全,但整体思想理解到位,由于状态图太多,此处不能一一列出。图中带有叉号的是本要扩展出新的节点,但是经过判定,此节点不合法,顾不能产生该节点与搜索树。
编程思路:
广度优先搜索算法:
步1:把初始节点S0放入open表中。
步2:若open表为空,则搜索失败,退出。
步3:取open表中前面一个节点N放入CLOSED表中,并冠以顺序编号n。
步4:若目标节点Sg=N则转步2
步6:宽展N,将其所有子节点配上指向N的指针依次放入open表尾部,转步2。
#include<queue>
#include<iostream>
#include "stdlib.h"
#include<stack>
using namespace std;
#define num 2
int X, Y; //X为A容器的容量,Y为B容器的容量
int Z; //Z为需要量出的用水量
struct Node {
int shui[2]; //用于存放两个容器的状态
struct Node* parent; //设置父节点
};
queue<Node> open; //open表用于存放由初始节点扩展出的所有子节点
queue<Node> close; //存放所有扩展出来的子节点,直到找到目标节点
stack<Node> shuchu; //用于输出最终结果
/*初始化AB容器的容量以及需要量出的水量*/
void chushihua(Node &S)
{
S.parent = NULL;
cout << "请输入A容器的容量:";
cin >> X;
S.shui[0]=0;
cout << "请输入B容器的容量:";
cin >> Y;
S.shui[1]=0;
cout << "请输入需要量出的水量";
cin >> Z;
}
bool judeglegal(Node S)
{
if (S.shui[0] == Z || S.shui[1] == Z)
return true;
else
return false;
}
/*量水操作*/
void move(Node &S)
{
for (int count = 0; count < 6; count++)
{
Node tempNode;
tempNode = S;
if (count ==0) //将A容器的水全部倒出
{
tempNode.shui[0] = 0;
}
if (count == 1) //将B容器的水全部倒出
{
tempNode.shui[1] = 0;
}
if (count == 2) //如果A容器为空,则将A容器接满水
{
tempNode.shui[0] = X;
}
if (count == 3) //如果B容器为空,则将B容器接满水
{
tempNode.shui[1] = Y;
}
if (count == 4) //B往A倒水
{
/*如果产生溢出或者刚好处于满的情况*/
if (S.shui[0] + S.shui[1] >= X)
{
tempNode.shui[0] = X;
tempNode.shui[1] = S.shui[0] + S.shui[1] - X;
}
/*不会发生溢出的时候*/
else
{
tempNode.shui[0] = S.shui[0] + S.shui[1];
tempNode.shui[1] = 0;
}
}
if (count==5) //A往B倒水
{
/*如果产生溢出或者刚好处于满的情况*/
if (S.shui[0] + S.shui[1] >= Y)
{
tempNode.shui[0] = S.shui[0] + S.shui[1] - Y;
tempNode.shui[1] = Y;
}
/*不会发生溢出的时候*/
else
{
tempNode.shui[0] = 0;
tempNode.shui[1] = S.shui[0] + S.shui[1];
}
}
/*判断由该节点产生的子节点是不是与该节点相同,或者与父节点相同,若都不相同,则生成新的节点*/
if (S.parent!=NULL&&(*S.parent).shui[0]==tempNode.shui[0]&&tempNode.shui[1]==(*S.parent).shui[1]&&S.shui[0]==tempNode.shui[0]&&S.shui[1]==tempNode.shui[1])
{
continue;
}
tempNode.parent = &S;
open.push(tempNode);
}
}
/*对open表和close表进行操作*/
void operatoropenclose(Node S)
{
open.push(S); //把初始节点放进open表中
while (true)
{
close.push(open.front());//将open表的第一个节点放入close表
open.pop(); //将该节点弹出
if (!judeglegal(close.back()))//如果该节点不是目标节点
{
move(close.back()); //扩展该节点
}
else
{
break;
}
}
/*查找到目标解后,将初始节点到目标节点所经过的节点存入shuchu表*/
shuchu.push(close.back());
Node & changeNode=close.back();
while (close.back().parent != NULL) {
changeNode = *close.back().parent;
shuchu.push(changeNode);
}
/*如果shuchu表不空,则存在问题的解*/
while (shuchu.size() != 0)
{
for (int i = 0; i < 2; i++)
{
cout << shuchu.top().shui[i];
}
shuchu.pop();
cout << "->";
}
cout << "成功!";
}
int main()
{
Node S0;
chushihua(S0);
cout << X << Y << Z << endl;
operatoropenclose(S0);
return 0;
}