作业一-B 隐式图问题

题目:

倒水问题

“fill A” 表示倒满A杯,"empty A"表示倒空A杯,“pour A B” 表示把A的水倒到B杯并且把B杯倒满或A倒空。

Input

输入包含多组数据。每组数据输入 A, B, C 数据范围 0 < A <= B 、C <= B <=1000 、A和B互质。

Output

你的程序的输出将由一系列的指令组成。这些输出行将导致任何一个罐子正好包含C单位的水。每组数据的最后一行输出应该是“success”。输出行从第1列开始,不应该有空行或任何尾随空格。

Sample Input

2 7 5
2 7 4

Sample Output

fill B
pour B A
success
fill A
pour A B
fill A
pour A B
success


思路:

概述:

该题是作业A题的变形,本质也是BFS问题,只不过隐式图问题。
隐式图是仅给出初始结点、目标结点以及生成子结点的约束条件(题意 隐含给出),要求按扩展规则应用于扩展结点的过程,找出其他结点, 使得隐式图的足够大的一部分编程显式,直到包含目标结点为止。
在该类问题中,可能出现的每个点的情况在初始是不知道的,只有在不断执行扩展规则后才可以得到。

数据结构

point:记录该点处的a,b中液体量
Q:存储要进行下一步扩展的点
map<point,point> from :记录第一次到达某个杯子状态的前一个杯子状态,同时可以记录该杯子状态是否被访问过
map<point,int> handle:记录第一次到达某个杯子状态的操作号

解法

step1:将两个杯子均为空的状态加入队列
step2:从队列中取出一个状态,判断是否有杯子中的水满足条件,有-》step3,无-》step4
step3: 对取出状态进行所有倒水操作,分别判断新的状态是否未到达,将满足条件的放入队列中
step4:递归输出从原点到终点的倒水路径


总结:

本题也可以直接使用高维数组记录


代码:

#include<iostream> 
#include<queue>
#include<map>
#include<string.h>
using namespace std;
struct point
{
	int a,b;
		bool operator<(const point &p) const
	{
		return a!=p.a?a<p.a:b<p.b;
	}
};
	queue<point> Q;	
	map<point,point> from;
	map<point,int> handle;
void print(point &p)//递归输出从原点到终点倒水的路径
{
	point s=from[p];
	if(from.find(s)==from.end()||(s.a==0&&s.b==0))//判断是否到达原点
	{
		switch(handle[p])
		{
//		case 1:cout<<"success"<<endl;break;
		case 2:cout<<"empty A"<<endl;break;
		case 3:cout<<"empty B"<<endl;break;
		case 4:cout<<"fill A"<<endl;break;
		case 5:cout<<"pour B A"<<endl;break;
		case 6:cout<<"fill B"<<endl;break;
		case 7:cout<<"pour A B"<<endl;break;			
		}

		return;
	}
	print(from[p]);
		switch(handle[p])
		{
//		case 1:cout<<"success"<<endl;break;
		case 2:cout<<"empty A"<<endl;break;
		case 3:cout<<"empty B"<<endl;break;
		case 4:cout<<"fill A"<<endl;break;
		case 5:cout<<"pour B A"<<endl;break;
		case 6:cout<<"fill B"<<endl;break;
		case 7:cout<<"pour A B"<<endl;break;			
		}

}
int main()
{
	int A,B,C;
	while(scanf("%d%d%d",&A,&B,&C)!=EOF)
	{
		while(!Q.empty())//清空Q、from、handle
			Q.pop();
		from.clear();
		handle.clear();
		point u,next;
		u.a=0;
		u.b=0;
		Q.push(u);
		while(!Q.empty())
		{
			point now=Q.front();
			Q.pop();
			if(now.a==C||now.b==C)//到达终点
			{
				print(now);	
				cout<<"success"<<endl;
				break;				
			}
				if(now.a>0)//将a倒掉
				{
					next.a=0;
					next.b=now.b;
					if(from.find(next)==from.end())//判断该状态是否被到达过
					{
						from[next]=now;
						handle[next]=2;
						Q.push(next);
					}
				}
		if (now.b > 0) //将b倒掉
		{
            next.b = 0;  
            next.a = now.a;
					if(from.find(next)==from.end())
					{
						from[next]=now;
						handle[next]=3;
						Q.push(next);
					}
        }
					if(now.a<A)//将b倒入a
					{
						next.a=A;
						next.b=now.b;
					if(from.find(next)==from.end())
					{
						from[next]=now;
						handle[next]=4;
						Q.push(next);
					}
           if (now.b != 0) 
            {
                if (now.a + now.b <= A) 
                {
                    next.a = now.a + now.b;
                    next.b = 0;
					if(from.find(next)==from.end())
					{
						from[next]=now;
						handle[next]=5;
						Q.push(next);
					}           			
                } else 
                {
                    next.a = A;
                    next.b = now.a + now.b - A;
					if(from.find(next)==from.end())
					{
						from[next]=now;
						handle[next]=5;
						Q.push(next);
					}
                }
            }											
					}
 if (now.b < B) //将a倒入b
        {
            next.a = now.a;
            next.b = B;
					if(from.find(next)==from.end())
					{
						from[next]=now;
						handle[next]=6;
						Q.push(next);
					}
            if (now.a != 0) 
            {
                if (now.a + now.b <= B) 
                {
                    next.a = 0;
                    next.b = now.a + now.b;
					if(from.find(next)==from.end())
					{
						from[next]=now;
						handle[next]=7;
						Q.push(next);
					}
                } else 
                {
                    next.a = now.a + now.b - B;
                    next.b = B;
					if(from.find(next)==from.end())
					{
						from[next]=now;
						handle[next]=7;
						Q.push(next);
					}
                }
            }
        }
  					
	//		cout<<now.a<<" "<<now.b <<endl;
	//		cout<<next.a<<" "<<next.b <<endl;			
			}
	}
 
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值