POJ 3414(BFS建树)

      这一题是典型的BFS建树的问题。首先,可选的操作只有FILL,DROP,POUR三种,而这三种又各自衍生出两个分类。那么,我们可以通过这6种操作不断地转换状态。而我们知道,已经得到过得状态再次得到时,就一定会产生圈,得不到最优解。所以利用一个数组储存看这个状态是否已经达到。

      对于每一个子状态,枚举所有的操作,将操作过后得到的新状态压进队列。同时储存得到状态的时间和方法。并且更新这棵树。当达到目标状态后,采用前序遍历的办法逐次打印所经历过的操作。

      由于用的是枚举,所以代码写得有点繁琐。

      

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<queue>
using namespace std;
bool flag,visited[105][105];
struct situation
{
	int a, b;
	int time;
	char last_act[15];
	situation *pa;
	void operator=(situation modol){
		a = modol.a;
		b = modol.b;
		time = modol.time;
		pa = modol.pa;
		strcpy_s(last_act, modol.last_act);
		return;    //重写赋值操作符简化代码
	}
}tree[105][105];
int a_vol, b_vol, g_vol;
queue<situation>list;
void print(int a, int b)
{
	if (tree[a][b].pa == NULL)return;
	else
	{
		print(tree[a][b].pa->a, tree[a][b].pa->b);
		printf("%s\n", tree[a][b].last_act);
	}
	return;//前序遍历这棵树构造路径
}
void bfs(situation leaf)
{
	situation temp;
	int tempa, tempb;
	if (leaf.a == g_vol || leaf.b == g_vol)//达到目标状态,开始输出
	{
		flag = true;
		cout << leaf.time << endl;
		print(leaf.a, leaf.b);
		return;
	}
		if (!visited[a_vol][leaf.b])//已经达到过的状态不再重复
		{
			visited[a_vol][leaf.b] = true;
			temp.a = a_vol; temp.b = leaf.b;
			strcpy_s(temp.last_act, "FILL(1)");
			temp.time = leaf.time + 1;
			temp.pa = &tree[leaf.a][leaf.b];
			tree[a_vol][leaf.b] = temp;
			list.push(temp);
		}
		if (!visited[leaf.a][b_vol])
		{
			visited[leaf.a][b_vol] = true;
			temp.a = leaf.a; temp.b = b_vol;
			strcpy_s(temp.last_act,"FILL(2)");
			temp.time = leaf.time + 1;
			temp.pa = &tree[leaf.a][leaf.b];
			tree[leaf.a][b_vol] = temp;
			list.push(temp);
		}
		if (!visited[leaf.a][0])
		{
			visited[leaf.a][0] = true;
			temp.a = leaf.a; temp.b = 0;
			strcpy_s(temp.last_act, "DROP(2)");
			temp.time = leaf.time + 1;
			temp.pa = &tree[leaf.a][leaf.b];
			tree[leaf.a][0] = temp;
			list.push(temp);
		}
		if (!visited[0][leaf.b])
		{
			visited[0][leaf.b] = true;
			temp.a = 0; temp.b = leaf.b;
			strcpy_s(temp.last_act, "DROP(1)");
			temp.time = leaf.time + 1;
			temp.pa = &tree[leaf.a][leaf.b];
			tree[0][leaf.b] = temp;
			list.push(temp);
		}
			tempa = min(a_vol, leaf.a + leaf.b);
			tempb = (leaf.b+leaf.a) - tempa;
			if (!visited[tempa][tempb])
			{
				visited[tempa][tempb] = true;
				temp.a = tempa; temp.b = tempb;
				strcpy_s(temp.last_act, "POUR(2,1)");
				temp.time = leaf.time + 1;
				temp.pa = &tree[leaf.a][leaf.b];
				tree[tempa][tempb] = temp;
				list.push(temp);
			}
			tempb = min(b_vol, leaf.a + leaf.b);
			tempa = (leaf.a+leaf.b) - tempb;
			if (!visited[tempa][tempb])
			{
				visited[tempa][tempb] = true;
				temp.a = tempa; temp.b = tempb;
				strcpy_s(temp.last_act, "POUR(1,2)");
				temp.time = leaf.time + 1;
				temp.pa = &tree[leaf.a][leaf.b];
				tree[tempa][tempb] = temp;
				list.push(temp);               //枚举各种情况,如果符合条件的即加入队列
		    }
	if (list.empty())return;//若队列为空,即进入死循环,不可能达到目的状态
	else
	{
		temp = list.front();
		list.pop();
		bfs(temp);
	}
	return;
}
int main()
{
	memset(visited, false, sizeof(visited));
	visited[0][0] = true;
	tree[0][0].a = tree[0][0].b = tree[0][0].time = 0;
    flag = false;

	cin >> a_vol >> b_vol >> g_vol;
	bfs(tree[0][0]);
	if (!flag)cout << "impossible" << endl;
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值