Online JudgeProblem SetAuthorsOnline ContestsUser
Web Board
Home Page
F.A.Qs
Statistical Charts
Problems
Submit Problem
Online Status
Prob.ID:
Register
Update your info
Authors ranklist
Current Contest
Past Contests
Scheduled Contests
Award Contest
User ID:
Password:
  Register

发一段有注释的代码纪念学习的第一道并查集

Posted by baicaitest at 2009-09-10 10:22:04 on Problem 1988
原作者选择了非递归的方法,对于我这种菜菜来说,开始费了一些力气.

#include<stdio.h>
#include<stdlib.h>
const int maxn=30002;
int p[maxn],num[maxn],sum[maxn];
void Makeset(int x)
{
     p[x]=-1;//根节点 ,上面的结点? 
     num[x]=0;//下家多少 ,或者距离root多远 
     sum[x]=1;//堆的大小
}
int Find(int x)//非递归压缩路径
{
     int r=x,s;
     s=0;
     while(p[r]!=-1)//r为根结点
     {
      r=p[r];
      s=s+num[r];
      }
     s=s-num[r];//这一步操作使s成为一堆负数数的和——距离root的和 
     while(x!=r)
     {
      int q=p[x];//q为x的父节点
      p[x]=r;
      num[x]=s+num[x];//更新num[x],使num[x]的性质得以满足,
      s=s-num[q];
      if(s==0)//更新到不需要更新为止 
      break;
      x=q;
      }
    return r;        
}    
int Union(int a,int b)//Move操作 
{
    int t1,t2;
    t1=Find(a);
    t2=Find(b);
    p[t2]=t1;
    sum[t1]+=sum[t2];//sum[x]表示该堆的个数
    num[t1]=num[t1]+sum[t2];//显然num值为自己的加后来的 
    num[t2]=num[t2]-num[t1];////距离root 
//    printf("num[t2]:%d\n",num[t2]);
    return 0;
}
int count(int x)
{
 int r,s;
 r=Find(x);
  s=0;
  
 while(x!=-1)//只可能有run once& twice两种可能 
 {
   s=s+num[x];
   x=p[x];//x的上家成为x,上倒腾。 
   }
   return s;
}
 int main()
{  
     int i,t,x,y;
     char ch[3];
     for(i=1;i<=30000;i++)
     Makeset(i);//堆初始化 
     scanf("%d",&t);
     while(t--)
     {
      scanf("%s",ch);
      if(ch[0]=='M')
      {
      scanf("%d%d",&x,&y);
      Union(x,y);
      }
      else
      {
      scanf("%d",&x);
      printf("%d\n",count(x));
      }
}    
     return 0;
}

Followed by:

Post your reply here:
User ID:
Password:
Title:

Content:

Home Page   Go Back  To top


All Rights Reserved 2003-2013 Ying Fuchen,Xu Pengcheng,Xie Di
Any problem, Please Contact Administrator