poj 1182 并查集

来源:互联网 发布:网络爬虫基本原理 编辑:程序博客网 时间:2024/04/29 08:19


1
#include<iostream> 2 #include<stdio.h> 3 #include<string> 4 #include<string.h> 5 #include<map> 6 #include<math.h> 7 #define N 50005 8 using namespace std; 9 // rank[x] 表示 parent[x]与x 的关系, rank[x]=0 同类, rank[x]=1 根吃x, rank[x]=2 , x吃根10 int rank[N]; 11 int parent[N];12 int n;13 void init()14 {15 for(int i=1;i<=n;i++)16 {17 parent[i]=i;18 rank[i] = 0;19 }20 }21 int Find(int x)22 {23 if(x== parent[x]) return x;24 int temp_parent=parent[x];25 parent[x]=Find(parent[x]);26 rank[x]=(rank[temp_parent]+rank[x])%3; //因为,根节点连到另一个新的根节点后,根节点有变化,故需要更新x到新节点的关系27 return parent[x];28 }29 void Union(int x, int y,int D)30 {31 int xf=Find(x);32 int yf=Find(y);33 parent[xf]=yf;34 rank[xf]=(rank[y]+D-rank[x]+3 )%3; // 更新根节点到另一个根节点的关系35 }36 int main()37 {38 int m;39 scanf("%d%d",&n,&m);40 41 int i,j,D,u,v,sum=0;42 init();43 for(int i=0;i<m;i++)44 {45 scanf("%d%d%d",&D,&u,&v);46 if(u>n || v>n ||(D==2 && u==v)) {47 sum++;48 continue;49 }50 int uu= Find(u);51 int vv= Find(v);52 if(uu == vv) //属同一子集,可以判断关系53 {54 if((rank[u] - rank[v] +3)%3 !=D-1)55 sum++;56 }57 else 58 {59 60 Union(u,v,D-1);61 }62 }63 printf("%d\n",sum);64 65 return 0 ;66 }

 1.p[x]表示x的根结点。r[x]表示p[x]与x的关系。r[x] == 0 表示p[x]与x同类;1表示p[x]吃x;2表示x吃p[x]。

2 怎样划分 集合。

注意,这里不是根据x与p[x]是否是同类来划分。而是根据“x与p[x]能否确定两者之间的关系”来划分,若能确定x与p[x]的关系,则它们同属一个集合。

 3.怎样判断一句话是不是假话?
        假设已读入 D , X , Y , 先利用find_set()函数得到X , Y 所在集合的代表元素 rx , ry ,若它们在同一集合(即 rx == ry )则可以判断这句话的真伪( 据 2. ).
        若 D == 1 而 r[X] != r[Y] 则此话为假。(D == 1 表示X与Y为同类,而从r[X] != r[Y]可以推出 X 与 Y 不同类。矛盾。)
        若 D == 2 而 r[X] == r[Y] (X 与Y为同类)或者 r[X] == ( r[Y] + 1 ) % 3 (Y吃X )则此话为假。即x不吃y ,  y!=(x+1)%3

 

若 ( r[Y] - r[X] + 3 ) % 3 != D - 1 ,则此话为假。(来自poj 1182中的Discuss )

 5.其他注意事项:
        在union_set( rx , ry )过程中若将S(ry)合并到S(rx)上,则相应的r[ry]必须更新为ry相对于rx的关系。怎样得到更新关系式?用向量运算。
         现在已知关系: rx与x, ry与y, x与y,现在求rx与ry的关系。学过向量应该能做出来吧。。。

     //以下来自poj 1182 中的Discuss

 在find_set( x )过程中要更新所有从x到rx路径上的结点与代表元素的相对关系。

0 0
原创粉丝点击