题目地址:
http://poj.org/problem?id=1208
The Blocks Problem
问题描述:
问题是解析一系列命令,指示机器人手臂如何操纵位于平台上的块。 最初在表上有n个块(编号从0到n-1),块bi与块bi + 1相邻,所有0 <= i <n-1,如下图所示:
操纵块的机器人手臂的有效命令是:
move a onto b:
其中A和B是块编号,在将堆积在块A和B顶部的任何块返回到它们的初始位置之后,将块A放到块B上。
move a over b:
其中A和B是块编号,在将块A顶部堆叠的任何块返回到其初始位置之后,将块A放入包含块b的堆栈的顶部。
pile a onto b:
其中A和B是块编号,移动由块A组成的块堆,以及堆积在块A上方的任何块到块B上。 在堆发生之前,块B顶部的所有块都移动到它们的初始位置。 上面堆叠的块在移动时保持其顺序。
pile a over b:
其中A和B是块编号,将由块A组成的块堆和堆积在块A上方的任何块放到包含块B的堆栈顶部。 块上方堆叠的块在移动时保留其原始顺序。
quit:
终止块世界中的操作。
任何A = B或其中A和B在同一堆块中的命令都是非法命令。 应忽略所有非法命令,并且不应影响块的配置。
输入描述:
输入以行上的整数n开始,表示块世界中的块数。 您可以假设0 <n <25。
块的数量后跟一系列块命令,每行一个命令。 您的程序应该处理所有命令,直到遇到quit命令。
您可以假设所有命令都是上面指定的格式。 没有语法错误的命令。
输出描述:
输出应该包含块世界的最终状态。 应该出现编号为i(0 <= i <n,其中n是块数)的每个原始块位置,紧接着是冒号。 如果它上面至少有一个块,则冒号后面必须跟一个空格,后面跟着一个块列表,这些块表示堆叠在该位置,每个块号与其他块号分隔一个空格。 不要在行上放置任何尾随空格。
每个块位置应该有一行输出(即,n行输出,其中n是第一行输入上的整数)。
样例输入:
10
move 9 onto 1
move 8 over 1
move 7 over 1
move 6 over 1
pile 8 over 6
pile 8 over 5
move 2 over 1
move 4 over 9
quit
样例输出:
0: 0
1: 1 9 2 4
2:
3: 3
4:
5: 5 8 7 6
6:
7:
8:
9:
思路:
我的思路是使用多条链表来解决。链表的每个节点的数据类型为一个结构体node,结构体内有两个基本数据类型成员:一个整型data(用来存放木块的编号),和一个指向node的指针next(用来存放下一个木块的地址)。 然后,在每个木块初始位置上都设置一条链表(一条链表就表示为这个位置上的木块放置情况,节点表示木块儿,并且认为靠近链表头节点的节点是较下方的木块。),也就是n条链表,例如输入样例,程序就会生成10条链表。每个链表的初始化为:链表中只有一个节点,这个节点的data为这个位置的编号,这个节点的next为NULL,例如,位置3上的链表初始化后只有一个节点,data为3,next为NULL。并且认为靠近链表头节点的节点是较下方的木块。
接下来输入n和命令字符串,根据命令字符串来选择4个程序中的1个来执行。
当命令为 move A onto B:
根据题意,先将A和B木块上面木块都归位,就是说,将A节点的后面的节点都去掉,并放回编号为它们各自本身的位置的链表。具体操作为:首先,先将a木块上方木块归位,从a节点往后遍历这条链表,对每个遍历到的节点:next设为NULL,并将编号为“该节点的data”的链表的链表头节点设置为该节点。然后将a节点的next设为NULL。a木块上面木块就归位完毕了。对b节点同理。此时已经将ab木块上面的木块放回了初始位置,接下来,只需要将b节点的next指向a节点(意义为将a木块放在b木块上),并且将指向b节点的节点next设为NULL(如果没有指向b节点的节点,就将初始时所在的那条链表头节点设置为NULL,即设为空链表)(这个操作的意义为更新链表的尾节点), 完成。
当命令为move A over B:
跟上一个不同的是,这回不需要将b木块上面的木块放回初始位置,因为是将a木块放在b木块所在块堆的最顶上。 a木块上面的木块还是需要放回初始位置,方法和上文相同。接下来,a木块上已经没有木块,看b节点所在链表,找到该链表的尾节点,将尾节点的next指向a木块就完成了(意义为将a木块放在b木块块堆上), 并将指向a节点的节点next设为NULL(如果没有指向a节点的节点,就将初始位置的那条链表头节点设置为NULL,即设为空链表)(这个操作的意义为更新链表的尾节点), 完成。
当命令为pile A onto B:
跟第一个不同的是,这回不需要将a木块上面的木块放回初始位置,因为是将a木块以及a木块以上的所有木块全部拿起,放在b木块上。 b木块上面的木块还是需要放回初始位置,方法和上文相同。现在,b木块上已经没有木块。接下来,将a木块块堆拿起,即把指向a节点的节点的next设置为NULL。然后放在b木块上,即将b节点的next指向a节点, 完成。
当命令为pile A onto B:
这个命令应该是最简单的,因为这回对ab木块,都不需要将上面的木块放回初始位置了。所以用同样的方法找到b节点的所在链表的链表尾节点,然后把a节点和后边所有节点这个部分链,接在找到的尾节点上,就完成了。
需要注意的是:
1.这道题还需要判断命令是否合法(如果ab在一个链表里就不合法了)。我的方法是:在执行命令之前,判断ab所在链表的链表尾节点是否相同,相同即不合法,不相同即合法。
2.在执行每条命令之前,需要找到四个地址,存到指针里,分别为a节点的地址,指向a节点的节点的地址,b节点的地址,指向b节点的节点的地址。
另外写代码有点略长,不够精炼,有些地方可能不够专业,毕竟刚大一,有错误或者重复计算的地方,希望大家能指出,谢谢~
还有,这里题目描述都是google翻译的,原文在上文网址中。。。
ac代码:
#include<cstdio>
#include<cstdlib>
#include<cstring>
using namespace std;
struct node
{
int data;
struct node *next;
};
int main()
{
struct node *p, *q, *t, *head[30], *pa, *pb, *qa, *qb, *tt;
int i, j, d, n;
scanf("%d", &n);
qa = NULL;
qb = NULL;
for(i = 0; i <= n-1; i++)
{
p = (struct node *)malloc(sizeof(struct node));
p -> data = i;
p -> next = NULL;
head[i] = p;
}
char aa[10], bb[10];
int a, b;
getchar();
while(scanf("%s", aa))
{
qa = NULL;
qb = NULL;
if(strcmp(aa, "quit") == 0)
{
break;
}
scanf("%d%s%d",&a, bb, &b);
if(a == b)
continue;
for(i = 0; i <= n-1; i++)
{
t = head[i];
while(t != NULL)
{
if(t->data == a)
{
pa = t;
}
if(t->next != NULL && t->next->data == a)
{
qa = t;
}
if(t->data == b)
{
pb = t;
}
if(t->next != NULL && t->next->data == b)
{
qb = t;
}
t = t->next;
}
}
struct node *ta, *tb;
ta = pa;
while(ta->next != NULL)
{
ta = ta->next;
}
tb = pb;
while(tb->next != NULL)
{
tb = tb->next;
}
if(ta == tb)
continue;
if(strcmp(aa, "move") == 0)
{
if(qa != NULL)
{
qa->next = NULL;
}
else
{
head[pa->data] = NULL;
}
t = pa->next;
while(t != NULL)
{
head[t->data] = t;
tt = t->next;
t->next = NULL;
t = tt;
}
if(strcmp(bb, "onto") == 0)
{
t = pb->next;
while(t != NULL)
{
head[t->data] = t;
tt = t->next;
t->next = NULL;
t = tt;
}
pb->next = pa;
}
else if(strcmp(bb, "over") == 0)
{
t = pb;
while(t->next != NULL)
{
t = t->next;
}
t->next = pa;
pa->next = NULL;
}
}
else if(strcmp(aa, "pile") == 0)
{
if(qa != NULL)
{
qa->next = NULL;
}
else
{
head[pa->data] = NULL;
}
if(strcmp(bb, "onto") == 0)
{
t = pb->next;
while(t != NULL)
{
head[t->data] = t;
tt = t->next;
t->next = NULL;
t = tt;
}
pb->next = pa;
}
else if(strcmp(bb, "over") == 0)
{
t = pb;
while(t->next != NULL)
{
t = t->next;
}
t->next = pa;
}
}
}
for(j = 0; j <= n-1; j++)
{
t = head[j];
printf("%d:", j);
while(t != NULL)
{
printf(" %d", t->data);
t = t->next;
}
printf("\n");
}
return 0;
}