• hdu 3047–Zjnu Stadium(带权并查集)


    题目大意:

    有n个人坐在zjnu体育馆里面,然后给出m个他们之间的距离, A B X, 代表B的座位比A多X. 然后求出这m个关系之间有多少个错误,所谓错误就是当前这个关系与之前的有冲突。

    分析:

    首先我们假设所有节点均在不同行的0位置,即rank[]初始化需为零,同时p[]需要初始化为-1,表示各个节点之间不存在联系,相互独立;

    接下来,我们获取信息:A B X;那么我们需要检查 :

    1. 如果A B的father相同,那么说明前面的一组(A B X)直接或者间接地更新了A B间的距离,我们便需要检查已经存在距离,和最新输入的X是否相违背;

    2. 如果A B的father不相同,那么是否能直接把B以及与B同在一个集合的元素加入A所在的集合,而不发生冲突呢?

        这里的冲突指的是:假设节点1是根节点,已知节点2距离节点1 200m,现在读取新的输入:1 3 200 。我们发现,节点2,3到达节点1 的距离相同,同一个位置上出现了两个节点,这显然与题意相违背,即冲突。

    【问题】假设我们发现A属于ra集合,B属于rb集合,如何合并两个独立的集合ra,rb?

    [mergeleft{ {A,B|A in ra,B in rb} ight}]

    事实上将集合rb并入集合ra是容易的,但是我们需要更新集合rb中的rank[],因为根元素变化了。

    现在集合rb中的根元素的rank值不再是0了(自己到自己的距离为0),而是变成了该根元素到达ra集合中的根元素的距离。

    假设输入为 A B X,rb为B所在集合的根元素,那么该根元素的更新公式为:
    [rankleft[ {rb} ight] = left( {rankleft[ A ight] + rankleft[ B ight] + X + 300} ight)\% 300]

    【问题】那么rb集合中的剩下的元素如何更新?何时更新?

    我们可以在下一次的find操作中更新集合rb中的距离值,这样的话,通过路径压缩的方法,我们可以实现:

    集合rb中的元素的father指向集合ra中的根元素,集合rb中的元素的rank表示距离集合ra中的根元素的距离。

    更新公式:(x为当前节点,p[x]表示x的父节点)
    [rankleft[ x ight] = left( {rankleft[ x ight] + rankleft[ {pleft[ x ight]} ight]} ight)\% 300]

    题解:

    #include<iostream>
    #include<cstdio>
    using namespace std;
    #define MOD 300
    #define maxn 50001
    int p[maxn];
    int rank[maxn];
    void init(int n){
    	memset(p,-1,sizeof(p));
    	memset(rank,0,sizeof(rank));
    }
    int find(int x){
    	if(p[x]==-1)
    		return x;
    	else{
    		int tmp=p[x];
    		p[x]=find(p[x]);
    		rank[x]=(rank[x]+rank[tmp])%MOD;
    		return p[x];
    	}
    }
    bool judge(int a,int b){
    	return find(a)==find(b);
    }
    
    bool Union(int a,int b,int x){
    	int ra=find(a);
    	int rb=find(b);
    	if(ra==rb){
    		if((rank[b]-rank[a]+MOD)%MOD!=x)
    			return false;
    		return true;
    	}
    	rank[rb]=(rank[a]-rank[b]+x+MOD)%MOD;
    	p[rb]=ra;
    	return true;
    }
    
    int main(){
    	int n,m;
    	while(scanf("%d %d",&n,&m)!=EOF){
    		int a,b,x;
    		int cnt=0;
    		init(n);
    		while(m--){
    			scanf("%d %d %d",&a,&b,&x);
    			if(!Union(a,b,x))
    				cnt++;
    		}
    		printf("%d
    ",cnt);
    	}
    }
  • 相关阅读:
    Android高手进阶教程(五)之----Android 中LayoutInflater的使用!
    APDPlat
    微博项目学习笔记
    iOS极光推送进一部使用(重点)
    iOS 打测试包
    自定义UICollectionViewFlowLayout
    解决UITableview 底部留白
    NSAttributedString 富文本样式
    OC排序算法
    CALayer,,,CATextLayer,,,CAShapeLayer,, CAGradientLayer
  • 原文地址:https://www.cnblogs.com/ZJUT-jiangnan/p/3958112.html
Copyright © 2020-2023  润新知