1. 程式人生 > >hdu1325 Is It A Tree?並查集

hdu1325 Is It A Tree?並查集

題目地址

單看題目的話和hdu1272是一樣的。但是hdu1272的博文中我也說了,資料比較水,所以我用非並查集的方法就AC了。但是這題的資料沒那麼水,要用到並查集來解。這題的盲點和重點有這麼幾個:

  • 輸入不是以-1 -1結束,而是以兩個負數結束
  • 需要用並查集來判斷是不是隻有一個“根”
  • 需要判斷所有節點的入度是否大於1
  • 本題輸入的格式,也要注意一下。
可以先忽略圖中的方向的。因為如果有環的話,就變成圖了,若嚴格的按照用parent陣列來儲存上一級父節點的方法,會有衝突。

比如這個圖中,8的父節點有兩個那麼parent[8]應該如何儲存呢??所以我們可以把它看成無向圖,無所謂父子,只需把關係集合merge合併就好了。這種有多個父節點的情況,就使用一個記錄入度的陣列來標記就好了。

#include<iostream>
using namespace std;
const int MAX=1000;
int rudu[MAX+10];//入度
int parent[MAX+10];
int root[MAX+10];//儲存是否為根
bool flag = true;
int r=0;
int getParent(int a)
{
	int k=parent[a];
	if(parent[a]!=a)
	{
		parent[a]=getParent(parent[a]);
	}
	return parent[a];
}
void merge(int a,int b)
{
	int p1=getParent(a);
	int p2=getParent(b);
	if(p1==p2)
		return;
	parent[p1]=p2;
	root[p2]=1;
	root[p1]=0;
}
void init()
{
	r=0;
	flag = true;
	for(int i=0;i<=MAX;i++)
	{
		parent[i]=i;
		rudu[i]=0;
		root[i]=0;
	}
}

void main()
{
	int a,b,c=1;

	init();
	while(cin>>a>>b,a>=0&&b>=0)
	{
		if(!a&&!b)
		{
			for(int i=0;i<=MAX;i++)
			{
				if(rudu[i]>1)
					flag = false;
				if(root[i])
					r++;
			}
			if(r>1)
				flag=false;
			if(flag)
				cout<<"Case "<<c++<<" is a tree."<<endl;
			else
				cout<<"Case "<<c++<<" is not a tree."<<endl;
			init();
			continue;
		}
		if(getParent(a)!=getParent(b))
			merge(a,b);
		rudu[b]++;
	}
}