POJ 3414 得到想要的容量 BFS

39 篇文章 0 订阅

题目在: http://poj.org/problem?id=3414


题目的大意是: 给你两个容量固定的烧杯,容量分别是A和B,如何得到体积是C的水,只有如下操作是合法的

1. 装满A,从水源处获得

2. 装满B

3, 将A倒给B,倒完后或者B倒满了,或者A空了

4. 将B倒给A,倒完后或者A满了,或者B空了

5. 将A清空

6. 将B清空


求出最少的步骤可以使得从最初两个空杯,得到体积为C水,其中容量为C的水,可以放在任何一个容器中。

Sample Input

3 5 4

Sample Output

6
FILL(2)
POUR(2,1)
DROP(1)
POUR(2,1)
FILL(2)
POUR(2,1)


分析:此题的分类是BFS,不过自己想半天也没有想清楚如何BFS,看了discussion里的一些提示,才所有顿悟。

在BFS的过程中,当前的状态是两个数,ca,cb,描述当前a烧杯中有水ca,b烧杯中有水cb。

因为下一步只有六种选择的情况,所以我们把这六个情况都枚举出来,例如当权枚举到stepi,如果经过这一步的操作,达到的状态出现过,我们就不将新状态放入队列,

否则作为新的状态放入队列。


我们要记录路径,所以还要保留每个状态之前的状态,同时也有保存到达当前状态的时候,经历了多少步。

所以每个状态里面的有如下值:

1. 两个烧杯的容量 2. 前一个状态 3.到当前状态步骤 4 到这个状态所采用的操作。


代码如下:

#include <stdio.h>
#include <memory.h>

#define MAX_NUM 101
#define MAX_Q MAX_NUM * MAX_NUM

enum OPERATION
{
	FILL1 = 0, FILL2, POUR12, POUR21, DROP1, DROP2, NONE
};

struct Step
{
	int liter1;
	int liter2;
	int stepID;

	OPERATION operation;
	int previous;

	Step()
	{

	}
	Step(int l1, int l2, int step, OPERATION op, int previous)
	{
		liter1 = l1;
		liter2 = l2;
		stepID = step;
		operation = op;
		this->previous = previous;

	}
};

struct Queue
{
	Step steps[MAX_Q];
	int front;
	int rear;


	void ini()
	{
		memset(steps, 0, sizeof(steps));
		front = rear = 0;
	}

	void push(int l1, int l2, int step, int privous, OPERATION op)
	{
		steps[rear++] = Step(l1, l2, step, op, privous);
	}


};

bool visit[MAX_NUM][MAX_NUM];
Queue q;

void PrintPath(int i)
{
	if( i == -1)
	{
		return ;
	}
	PrintPath(q.steps[i].previous);

	switch(q.steps[i].operation)
	{
	case FILL1:

		printf("FILL(1)\n");
		break;

	case FILL2:
		printf("FILL(2)\n");
		break;

	case POUR12:
		printf("POUR(1,2)\n");
		break;

	case POUR21:
		printf("POUR(2,1)\n");
		break;

	case DROP1:
		printf("DROP(1)\n");
		break;

	case DROP2:
		printf("DROP(2)\n");
		break;
	}
}
void BFS(int a, int b, int c)
{
	q.ini();
	q.push(0, 0, 0, -1, NONE);
	visit[0][0] = true;
	Step nxt,current;
	while(q.rear > q.front)
	{
		current = q.steps[q.front++];
		if(current.liter1 == c || current.liter2 == c)
		{
			break;
		}
		OPERATION iOp;
		for( int i = 0; i < 6; i++)
		{
			iOp = (OPERATION)i;
			nxt = current;
			switch(iOp)
			{
			case FILL1:
				{
					//fill glass a
					if( !visit[a][nxt.liter2] )
					{
						q.push(a, nxt.liter2, current.stepID + 1, q.front - 1, FILL1);
						visit[a][nxt.liter2] = true;
					}
					break;
				}
			case FILL2:
				{
					if( !visit[nxt.liter1][b] )
					{
						q.push(nxt.liter1, b, current.stepID + 1, q.front - 1, FILL2);
						visit[nxt.liter1][b] = true;
					}
					break;
				}
			case POUR12:
				{
					int newA = current.liter1;
					int newB = current.liter2;
					if(newA + newB > b)
					{
						newA = newA + newB - b;
						newB = b;
					}
					else
					{
						newB = newA + newB;
						newA = 0;
						
					}
					if(!visit[newA][newB])
					{
						q.push(newA, newB, current.stepID + 1, q.front - 1, POUR12);

						visit[newA][newB] = true;
					}
					break;
				}
			case POUR21:
				{
					int newA = current.liter1;
					int newB = current.liter2;

					if(newA + newB > a)
					{
						
						newB = newA + newB - a;
						newA = a;
					}
					else
					{
						newA = newA + newB;
						newB = 0;
					}

					if(!visit[newA][newB])
					{
						q.push(newA, newB, current.stepID + 1, q.front - 1, POUR21);

						visit[newA][newB] = true;
					}
					break;
				}
			case DROP1:
				{
					if( !visit[0][nxt.liter2] )
					{
						q.push(0, nxt.liter2, current.stepID + 1, q.front - 1, DROP1);
						visit[0][nxt.liter2] = true;
					}
					break;
				}
			case DROP2:
				{
					if( !visit[nxt.liter1][0] )
					{
						q.push(nxt.liter1, 0, current.stepID + 1, q.front - 1, DROP2);
						visit[nxt.liter1][0] = true;
					}
					break;
				}
			}
		}
	}
	if( q.front == q.rear)
	{
		printf("impossible\n");
	}
	else
	{
		printf("%d\n", q.steps[q.front-1].stepID);
		PrintPath(q.front-1);
	}
}

int main()
{

	int a,b,c;

	while(scanf("%d%d%d", &a, &b, &c) != EOF)
	{
		memset(visit, 0, sizeof(visit));
		BFS(a, b, c);
	}
	return 0;
}

编写的时候犯了好几个bug,导致半天都调不通

bug1, 在newA newB赋值的时候,将顺序写错,忽略了两个值存在依赖关系的事实。

bug2, 最后遍历的时候,没有写front-1, 其实front在上次取完了的时候,就已经-1.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值