標題這幾題都是去判斷樹的,只是輸出不一樣
要用定義去做樹,那肯定要知道樹是什麼
學習的時候很迷茫是沒搞清楚大方向
什麼是大方向呢?
兩個字:圖論
樹肯定是圖,但圖不一定是樹
搞清楚這麼幾個知識點就可以愉快的做這題了
- 什麼是度?度就是邊。度分爲入度和出度(出邊和入邊)。我們這裏有個點V,指向V的邊就是入度,從V指出去的是出度
- 什麼是樹?只有一個點入度爲0,其它點入度爲1的圖就是樹。
好了,一旦解決了什麼是樹,那所有問題解決了。什麼?你說還不懂?那我給你一個個列出來
- 只有一個點入度爲0保證了樹有且只有一個根節點
- 除根節點外,其它點都有入度,保證了這一定是個連通圖(仔細想就知道了,有入度肯定連着)
- 除根節點外,其它點的入度都是1,保證每個點的根節點只有一個(這也保證了圖不可能有環)
所以呢,並查集也可以做這題,操作就是:
- 連通分量爲1 (Find(i) == i的數量只有1)
- 且圖無環。(在合併操作裏面可以判斷)
當然了,這題有個很鬼的地方----就是沒有點也算樹。
講道理圖不可能是空集,既然出題人覺得 空即是色 的話,那就加個特判吧……
這裏先列出用樹的性質做的代碼。
#include <bits/stdc++.h>///注意poj不能用萬能頭,自行更改吧
using namespace std;
int T,n,a,b;
int e[100005];///入度
int book[100005];///標記這個點是否出現
int main()
{
int mx=0;///我要遍歷存在的點。。這裏是用數組下標,所以我要保存遍歷到哪裏
int cnt=1;///這個just是用來輸出的時候看是第幾個例子而已……不用管
int isp=1;///這就是判斷是不是空集的標記
while(scanf("%d%d",&a,&b)!=EOF)
{
if(a+b<0)break;///-1 -1的時候結束
if(a==0 && b==0)///兩個都是0的時候判斷
{
int ans=0;///入度爲0的個數(有幾個根,很明顯只能有一個根)
int flag=1;///是否除了根節點以外都是入度爲1的呢?
for(int i=1;i<=mx;i++)
{
if(book[i] && e[i]==0)///判斷出現並且入度爲0,那就是根
{
ans++;
}
else if(book[i] && e[i]!=1)///不是根,那就判斷入度是不是1
{
flag=0;
}
}
///hdu 1272的只有輸出不一樣!(HDU1325)(POJ1308)都是這個板子
if((flag==1 && ans==1) || isp)printf("Case %d is a tree.\n",cnt);
else printf("Case %d is not a tree.\n",cnt);
///這些都是初始化
memset(e,0,sizeof(e));
memset(book,0,sizeof(book));
mx=0;
cnt++;
isp=1;
}
else{
isp=0;
e[b]++;///入度
book[a]=1;///標記這個點是否出現
book[b]=1;
mx=(max(a,max(mx,b)));
}
}
return 0;
}