How Many Answers Are Wrong(邊帶權並查集)

題目鏈接

http://acm.hdu.edu.cn/showproblem.php?pid=3038

根據前面的回答判斷下一個回答是否矛盾,因爲判斷下一個回答要根據前面的回答,所以用並查集來記錄前面數之間的關係,如果根據前面數的關係不能判斷出這組數據的答案,那就把這組數據也加入到並查集裏,如果能判斷出答案,但是答案錯誤,那麼res++,下面舉一個栗子
在這裏插入圖片描述
如果我在前面有輸入a,c和a,b之間的關係,在這一組數據中輸入了b,c的關係,用V(a,b)代表a,b之間的距離,那麼就有V(a,c)-V(a,b)==V(b,c),如果不符合,res++
輸入三個數digit1,digit2,distance,就是[digit1,digit2]的和爲distance,可以理解爲digit2比(digit1-1)這個數大distance,用sum數組來儲存權值"distance",這裏就有sum[digit1-1]=distance。
但是在並查集查找的時候,不但要做路徑壓縮,壓縮的同時還要維護權值數組sum的值,這裏要用到向量的知識。舉個例子,digit1的祖先是x,digit2的祖先是y,這裏默認並查集合並時,x併到y上,但是光並上去不行啊,還得計算sum[x]的值,如何計算?看下面一張圖
在這裏插入圖片描述
在查找d1和d2的祖先的過程中,我們肯定知道[d1,x]和[d2,y]的權值,爲什麼要合併x和y?出現這種情況就是因爲輸入給出了d1,d2之間的關係,而且這種關係無法判斷真假,按真處理,加入並查集,那麼如何計算sum[x]?這時候就很明顯了,sum[x]就是[x,y]的和,通過向量,仍用V(a,b)來表示[a,b]之間的權值,V(x,y)=V(d2,y)+V(d1,d2)-V(d1,x)。
在d1,d2祖先相同的時候,如何判斷他們的權值V(d1,d2)是否正確呢?也是這個道理,看下面一張圖,因爲他們有公共祖先,證明他們的sum值肯定在查找祖先的過程中經過了維護,直接指向了y(這裏假設y爲公共祖先),就有
V(D1,y)-V(D2,y)==V(D1,D2),V(D1,D2)的值會在這組輸入數據中給出,根據這個進行判斷即可。
在這裏插入圖片描述

C

#include <stdio.h>	
#include <string.h>
#pragma warning(disable:4996)
int tree[200001],sum[200001];
int get(int digit)
{
	int root;
	if(tree[digit]==digit)
		return digit;
	root=get(tree[digit]);
	sum[digit]+=sum[tree[digit]];
	return tree[digit]=root;
}
int main(void)
{
	int N,M,i,res,digit1,digit2,distance,x,y;
	while(scanf("%d %d",&N,&M)!=EOF)
	{
		memset(sum,0,sizeof(sum));
		for(i=0;i<=N;i++)	//注意這裏的初始化,要從0開始,因爲下面有digit1--,這裏卡了我1小時WA
			tree[i]=i;		
		for(res=0,i=0;i<M;i++)
		{
			scanf("%d %d %d",&digit1,&digit2,&distance);
			digit1--;//注意這裏,[d1,d2]的距離可以理解爲d2比d1-1這個數大distance
			x=get(digit1);
			y=get(digit2);
			if(x!=y)	//如果祖先不相同,無法判斷,一律按正確處理,併入並查集,我這裏以默認x是y的後代,如果y是x的後代,向量計算將會改變,要注意表達式的變化
			{
				tree[x]=y;
				sum[x]=distance+sum[digit2]-sum[digit1];
			}
			else
				if(sum[digit1]-sum[digit2]!=distance)
					res++;
		}
		printf("%d\n",res);
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章