Cube Stacking
Time Limit: 2000MS | Memory Limit: 30000K | |
Total Submissions: 12537 | Accepted: 4200 | |
Case Time Limit: 1000MS |
Description
Farmer John and Betsy are playing a game with N (1 <= N <= 30,000)identical cubes labeled 1 through N. They start with N stacks, each containing a single cube. Farmer John asks Betsy to perform P (1<= P <= 100,000) operation. There are two types of operations:
moves and counts.
* In a move operation, Farmer John asks Bessie to move the stack containing cube X on top of the stack containing cube Y.
* In a count operation, Farmer John asks Bessie to count the number of cubes on the stack with cube X that are under the cube X and report that value.
Write a program that can verify the results of the game.
moves and counts.
* In a move operation, Farmer John asks Bessie to move the stack containing cube X on top of the stack containing cube Y.
* In a count operation, Farmer John asks Bessie to count the number of cubes on the stack with cube X that are under the cube X and report that value.
Write a program that can verify the results of the game.
Input
* Line 1: A single integer, P
* Lines 2..P+1: Each of these lines describes a legal operation. Line 2 describes the first operation, etc. Each line begins with a 'M' for a move operation or a 'C' for a count operation. For move operations, the line also contains two integers: X and Y.For count operations, the line also contains a single integer: X.
Note that the value for N does not appear in the input file. No move operation will request a move a stack onto itself.
* Lines 2..P+1: Each of these lines describes a legal operation. Line 2 describes the first operation, etc. Each line begins with a 'M' for a move operation or a 'C' for a count operation. For move operations, the line also contains two integers: X and Y.For count operations, the line also contains a single integer: X.
Note that the value for N does not appear in the input file. No move operation will request a move a stack onto itself.
Output
Print the output from each of the count operations in the same order as the input file.
Sample Input
6 M 1 6 C 1 M 2 4 M 2 6 C 3 C 4
Sample Output
1 0 2
题意:有n个从1到n编号的箱子,将每个箱子当做一个栈,对这些箱子进行p次操作,每次操作分别为以下两种之一:
1>输入 M x y:表示将编号为x的箱子所在的栈放在编号为y的箱子所在栈的栈顶.
2>输入 C x:计算编号为x的所表示的栈中在x号箱子下面的箱子数目.
做法:这里我主要是用路径压缩来解决问题。
定义一个节点,每个节点存储的内容有:父亲,孩子,跳跃父亲,跳跃孩子,跳跃父亲长度,跳跃孩子长度。
这里举个例子:
假如我要把上图的X和Y合并,那么假设当前2个集合的情况如上图所示。
这时候我先找到X最底下的孩子、Y最上面的父亲。接下来我们要把两者合并。
1.把X和Y连接起来,那么X的跳跃孩子就是Y,Y的跳跃父亲就是X。跳跃长度就是图中的3+1+1.
2.把X最底下的孩子和Y连起来
3.把Y最上面的父亲和X连起来
这样就可以达到一个路径压缩的过程,在查找孩子和父亲的时候就可以大大减少搜索长度。
#include <iostream>
using namespace std;
struct node
{
int fa,ch,up,dn,lu,ld; //父亲,孩子,跳跃父亲,跳跃孩子,跳跃父亲长度,跳跃孩子长度
node()
{
up=dn=lu=ld=-1; //初始化不存在
}
}num[30010];
int findf(int x,int &l) //l记录了长度
{
while(1)
{
if(num[x].up!=-1) //跳跃查找
{
l+=num[x].lu;
x=num[x].up;
}
else if(num[x].fa!=x)
{
x=num[x].fa;
l++;
}
else
break;
}
return x;
}
int findc(int x,int &l)
{
while(1)
{
if(num[x].dn!=-1) //跳跃查找
{
l+=num[x].ld;
x=num[x].dn;
}
else if(num[x].ch!=x)
{
x=num[x].ch;
l++;
}
else
break;
}
return x;
}
void insert(int x,int y)
{
int cl=0,fl=0;
int ch=findc(x,cl); //X最底下的孩子
int fa=findf(y,fl); //Y最上面的父亲
num[ch].ch=fa; //连接X最底下的孩子和Y最上面的父亲
num[fa].fa=ch;
num[x].dn=y; //连接X,Y
num[y].up=x;
num[x].ld=num[y].lu=cl+fl+1; //计算长度
num[ch].dn=y; //连接X最底下的孩子和Y
num[ch].ld=fl+1;
num[fa].up=x; //连接Y最上面的父亲和X
num[fa].lu=cl+1;
}
int cal(int x)
{
int len=0;
findc(x,len);
return len;
}
int main()
{
int m,x,y,i;
char str[3];
for(i=0;i<=30000;i++) //初始化父亲孩子
num[i].fa=num[i].ch=i;
scanf("%d",&m);
while (m--)
{
scanf("%s%d",str,&x);
if(str[0]=='C')
{
printf("%d\n",cal(x));
}
else
{
scanf("%d",&y);
insert(x,y);
}
}
return 0;
}
虽然这样可以优化时间,但是效果还不是很理想,500MS。
网上其他的做法可以参照:http://www.cppblog.com/koson/archive/2010/04/08/111946.aspx?opt=admin