您的位置:首页 > 其它

POJ 3414(BFS建树)

2015-08-03 07:35 363 查看
这一题是典型的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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: