poj 1988_并查集(*)
2013-05-02 10:24
288 查看
题目描述:
。。。。。tle了数次。。。
解题思路:
几个可以看出来属于并查集的题,但是有时效要求。如果没有时效要求的话,一个最直观的方法是可以直接用不压缩的并查集,最后找树的某个节点位于第几层即可;如果压缩的话,也可以加一个down[]数组来存要求的值,在每次做union的时候,把x点放在y点之上时更新所有x点所在子树的所有down值,但是这样更新耗费的时间大,会令整个复杂度就增加为n倍的原并查集的复杂度;因此需要想一想,如果开两个数组up[]和down[],每次union的时候,只更新底层子树根的down值,和底层子树根的up值(也就是每次合并之前,子树根的up和down值都是正确的),然后在最后求的时候,用find_set更新点的up值,令根down值减去节点的up值,即为节点的深度。
代码:
#include <stdio.h>
#include <stdlib.h>
#define N 30001
int set
, down
, up
;
int count, max=1;
int find_set(int x)
{
int tmp = set[x];
if(set[x]!=x)
{
set[x] = find_set(set[x]);
printf("find_set中更新:up[%d](%d) +=
up[%d](%d).\n",x,up[x],tmp,up[tmp]);
up[x] += up[tmp];
printf("find_set中更新后:up[%d] = %d.\n",x,up[x]);
}
return set[x];
}
void union_set(int x, int y) // m x y
{
int i;
int y1 = find_set(y);
int x1 = find_set(x);
//
for(i=1;i<=max;i++)
//x所在的树的每个点的down都要加上 1+down[y1]
//
if(find_set(i) == x1)
//
{
//
// printf("顶层树的%d点的原值(%d) 加上 底层树的最高值(1+y1[%d点]) %d =
",i,down[i],y1,1+down[y1]);
//
down[i] += 1+down[y1];
//
//printf("%d.\n",down[i]);
//
}
set[y1] = x1;
printf("归并%d(x)->%d(y)上,令set[%d](y1) =
%d(x1).\n",x,y,y1,x1);
printf("更新前:x1:down[%d] =
%d.\ty1:up[%d] = %d,down[%d] =
%d\n",x1,down[x1],y1,up[y1],y1,down[y1]);
up[y1] += down[x1];
down[x1] += down[y1];
printf("更新后:x1:down[%d] =
%d.\ty1:up[%d] = %d,down[%d] =
%d\n",x1,down[x1],y1,up[y1],y1,down[y1]);
}
main()
{
int p,i,x,y;
char str[2];
scanf("%d",&p);
for(i=1;i<N;i++)
{
set[i] = i;
down[i] = 1;
up[i] = 0;
}
for(i=1;i<=p;i++)
{
scanf("%s",str);
if(strcmp("M",str)==0)
{
scanf("%d %d",&x,&y);
max =
max>x?(max>y?max:y):(x>y?x:y);
union_set(x,y);
}
else
{
scanf("%d",&x);
count = down[find_set(x)]-up[x];
printf("%d\n",count-1);
}
}
//system("pause");
return 0;
}
。。。。。tle了数次。。。
解题思路:
几个可以看出来属于并查集的题,但是有时效要求。如果没有时效要求的话,一个最直观的方法是可以直接用不压缩的并查集,最后找树的某个节点位于第几层即可;如果压缩的话,也可以加一个down[]数组来存要求的值,在每次做union的时候,把x点放在y点之上时更新所有x点所在子树的所有down值,但是这样更新耗费的时间大,会令整个复杂度就增加为n倍的原并查集的复杂度;因此需要想一想,如果开两个数组up[]和down[],每次union的时候,只更新底层子树根的down值,和底层子树根的up值(也就是每次合并之前,子树根的up和down值都是正确的),然后在最后求的时候,用find_set更新点的up值,令根down值减去节点的up值,即为节点的深度。
代码:
#include <stdio.h>
#include <stdlib.h>
#define N 30001
int set
, down
, up
;
int count, max=1;
int find_set(int x)
{
int tmp = set[x];
if(set[x]!=x)
{
set[x] = find_set(set[x]);
printf("find_set中更新:up[%d](%d) +=
up[%d](%d).\n",x,up[x],tmp,up[tmp]);
up[x] += up[tmp];
printf("find_set中更新后:up[%d] = %d.\n",x,up[x]);
}
return set[x];
}
void union_set(int x, int y) // m x y
{
int i;
int y1 = find_set(y);
int x1 = find_set(x);
//
for(i=1;i<=max;i++)
//x所在的树的每个点的down都要加上 1+down[y1]
//
if(find_set(i) == x1)
//
{
//
// printf("顶层树的%d点的原值(%d) 加上 底层树的最高值(1+y1[%d点]) %d =
",i,down[i],y1,1+down[y1]);
//
down[i] += 1+down[y1];
//
//printf("%d.\n",down[i]);
//
}
set[y1] = x1;
printf("归并%d(x)->%d(y)上,令set[%d](y1) =
%d(x1).\n",x,y,y1,x1);
printf("更新前:x1:down[%d] =
%d.\ty1:up[%d] = %d,down[%d] =
%d\n",x1,down[x1],y1,up[y1],y1,down[y1]);
up[y1] += down[x1];
down[x1] += down[y1];
printf("更新后:x1:down[%d] =
%d.\ty1:up[%d] = %d,down[%d] =
%d\n",x1,down[x1],y1,up[y1],y1,down[y1]);
}
main()
{
int p,i,x,y;
char str[2];
scanf("%d",&p);
for(i=1;i<N;i++)
{
set[i] = i;
down[i] = 1;
up[i] = 0;
}
for(i=1;i<=p;i++)
{
scanf("%s",str);
if(strcmp("M",str)==0)
{
scanf("%d %d",&x,&y);
max =
max>x?(max>y?max:y):(x>y?x:y);
union_set(x,y);
}
else
{
scanf("%d",&x);
count = down[find_set(x)]-up[x];
printf("%d\n",count-1);
}
}
//system("pause");
return 0;
}
相关文章推荐
- HDU 2818&&POJ 1988 并查集简单应用
- HDU 2818&&POJ 1988 并查集简单应用
- poj&nbsp;1308&nbsp;Is&nbsp;It&nbsp;A&nbsp;Tree?(并查集)
- poj&nbsp;1182&nbsp;并查集
- poj&nbsp;2236&nbsp;并查集
- poj 1703 并查集的拓展
- poj 1611 并查集训练
- poj 1182 并查集经典题…
- POJ 2492 A Bug's Life(路径压缩并查集)
- POJ1988 并查集(3)
- poj&nbsp;1946&nbsp;Cow&nbsp;Cycl…
- poj&nbsp;1980&nbsp;Unit&nbsp;Fraction&nbsp;Partition…
- poj&nbsp;2418&nbsp;Hardwood&nbsp;Species
- POJ1703 && POJ2942 &&POJ 1182 并查集 这个做法挺巧妙
- poj 1988 Cube Stacking(带权并查集)
- hdu 1325&&poj 1308 并查集(未解决)(掌握率50%)
- 并查集 POJ 1988
- poj 1125 Stockbroker Grapevine
- poj 数论 Semi-prime H-numbers
- poj&nbsp;1860&nbsp;Currency&nbsp;Exchange(bellm…