算法谜题——三个水壶问题

问题:有一个充满水的8品脱的水壶和两个空水壶(容积分别是5品脱和3品脱)。通过将水壶完全倒满水和将水壶的水完全倒空这两种方式,在其中的一个水壶中得到4品脱的水。

解法:可以把每次三个水壶中水的量组成一个状态,比如初始状态为008,对应第一个水壶0品脱水,第二个水壶0品脱水,第三个水壶8品脱水。对题目的状态空间图进行广度优先遍历。当表示状态的数字中出现4时,即求出答案。

1、为了打印出倒水的过程,需要声明一个前置状态保存当前状态由哪个状态转换而来,然后就可以回溯到初始状态,打印出倒水过程。相当于树中的父结点。

2、可以声明一个map表,保存已有的状态,对已有的状态,就不再向下继续遍历,这样可以节省求解时间。

3、因为是广度优先遍历,所以第一次解得的答案所需的倒水的次数最少,解为最优解。



#include 
#include 
#include 
#define MaxFirst 3
#define MaxSecond 5
#define MaxThird 8
using namespace std;
 
class State
{
public:
	int second;
	int num[3];
	State* preState;
        static map mapping;

public:
	State(int first,int second,int third)
	{
		num[0]=first;
		num[1]=second;
		num[2]=third;	
	}
	void init()
	{		
		mapping[0]=MaxFirst;
		mapping[1]=MaxSecond;
		mapping[2]=MaxThird;
	}

	bool canPour(int from,int to)//判断是否可以从from水壶中倒水到to水壶中
	{
		if(num[from]==0)
		{
			return false;
		}

		if(num[to]==mapping[to])
		{
			return false;
		}
		else 
		{
			return true;
		}
	}
	void pour(int from,int to)//倒水过程
	{
		if(num[from]+num[to]>mapping[to])
		{
			num[from]=num[from]-(mapping[to]-num[to]);
			num[to]=mapping[to];
		}
		else
		{
			num[to]=num[to]+num[from];
			num[from]=0;
		}
	}

};
map State::mapping;

int main()
{
	map states;
	State *start=new State(0,0,8);
	start->init();
	State *state=start;
	State *endState=new State(8,8,8);//只有获得解endState才会改变,赋值全为8为了方便判断是否获得最终解
	vector action;//保存所有状态对象
	action.push_back(*start);//把初始状态先加入队列中
	int n=0;
	do{
		for(int i=0;i<3;i++)//双层循环为从i水壶中倒水入j水壶中
		{
			for(int j=0;j<3;j++)
			{
				if(i!=j)
				{
					if(state->canPour(i,j))
					{
						state->pour(i,j);
						if(states[state->num[0]*100+state->num[1]*10+state->num[2]]==0)//如果该状态不在hash表中,即为第一次出现该状态
						{
							states[state->num[0]*100+state->num[1]*10+state->num[2]]++;
							(state->preState)=new State(action[n]);
							action.push_back(*state);
							if(state->num[0]==4||state->num[1]==4||state->num[2]==4)//获得解
							{
								endState=state;
								i=4;
								break;	
							}
					    }
					}
				}
				*state=action[n];
			}			
		}
		n++;
	}while(endState->num[0]==8&&endState->num[1]==8&& nnum[0]<<" "<num[1]<<" "<num[2]<preState;
		cout<num[0]<<" "<num[1]<<" "<num[2]<num[2]!=8);
	return 0;
}


运行结果如图,从下往上即为倒水的过程

如果需要倒出水壶含7品脱的情况,把

if(state->num[0]==4||state->num[1]==4||state->num[2]==4)
中的4改成7,运行出结果如下:





你可能感兴趣的:(leetcode&&算法谜题)