倒水问题

Q:有A B两个杯子,A杯子 7 L,B杯子 9 L,如何得到 1 L水?

A:使用BFS或者DFS 边建立图,边搜索 有装 1 L水的杯子 的状态。(实际上该问题为多叉树结构,BFS类似于层次遍历,DFS类似于先续遍历,在遍历过程中建立 树 ,到有装 1 L水的杯子 的节点停止。)

给出代码及注释:

/**************************************************************************
                               PourWater.h
**************************************************************************/

#pragma once
#include "stdafx.h"
#include "iostream"

#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))

//动作                       初始化, A倒进B, B倒进A,  倒满A,   倒满B,  倒空A,   倒空B
char* const VActions[7] = { "INIT", "A_TO_B","B_TO_A","FILL_A","FILL_B","EMPTY_A","EMPTY_B"};


struct state	//两杯子的状态
{
	int A, B;			//俩杯子容积
	int a, b;			//俩杯子中剩余的水
	state* parent;		//指向上一个状态
	char* action;	    //刚刚执行的动作

	state(int _A, int _B) : A(_A), B(_B), a(0), b(0), parent(NULL), action(VActions[0]) {}
	state(int _a, int _b, state* _parent, char* _action) : A(_parent->A), B(_parent->B), a(_a), b(_b), parent(_parent), action(_action) {}

	state* nextState(int i) {	//执行某一动作后的状态, 如果检测到重复状态返回NULL
		if (1 == i) return checkPred(this, a - MIN(B - b, a), b + MIN(B - b, a), VActions[i]);
		if (2 == i) return checkPred(this, a + MIN(A - a, b), b - MIN(A - a, b), VActions[i]);
		if (3 == i) return checkPred(this, A, b, VActions[i]);
		if (4 == i) return checkPred(this, a, B, VActions[i]);
		if (5 == i) return checkPred(this, 0, b, VActions[i]);
		if (6 == i) return checkPred(this, a, 0, VActions[i]);
		return 0;
	}

	state* checkPred(state* S, int _a, int _b, char* _action) {	//执行某一动作后,其所有祖先不能出现过相同的状态,否则会死循环
		do
			if (S->a == _a && S->b == _b)  return 0; 
		while (S = S->parent);
		return new state(_a, _b, this, _action);
	}

	void backTrace(state* S) {	//打印以S为叶节点的 可行路径
		if(state* _S = S->parent) backTrace(_S);
		std::cout << "(A:" << S->a << ", B:" << S->b << ") " << S->action << std::endl;
	}
};


// A, B 为杯子容积, D 为目标水量
void pour(int A, int B, int D, state* S){
	state* V = NULL;
	for (int i = 1; i < 7; i++) {	//从S开始,可能1-6种状态(INIT状态只在最初始设置)
		if (S->a == D || S->b == D) { S->backTrace(S);   std::cout << std::endl;   break; }
		if (V = S->nextState(i)) pour(A, B, D, V);
	}
}

void pourWater(int A, int B, int D) {
	state* S = new state(A, B);	 //初始状态INIT
	pour(A, B, D, S);
}



/**************************************************************************
                               main
**************************************************************************/
int main()
{
    pourWater(7, 9, 1);
}

 给出可行解之一:

       上述方法基于DFS(仅仅考虑节点祖先的状态,而不考虑其他节点状态),给出所有不重复状态条件下的所有解;所以这些解是相对于祖先不重复状态的最优解。

       若要考虑所有情况下,不重状态的最优解,则需要基于BFS构造图(引入队列,层次遍历)。基于DFS的解 包含 基于BFS的解。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值