Is It A Tree?

题目

A tree is a well-known data structure that is either empty (null, void, nothing) or is a set of one or more nodes connected by directed edges between nodes satisfying the following properties.

There is exactly one node, called the root, to which no directed edges point.
Every node except the root has exactly one edge pointing to it.
There is a unique sequence of directed edges from the root to each node.
For example, consider the illustrations below, in which nodes are represented by circles and edges are represented by lines with arrowheads. The first two of these are trees, but the last is not.
图片说明
In this problem you will be given several descriptions of collections of nodes connected by directed edges. For each of these you are to determine if the collection satisfies the definition of a tree or not.

分析

题意很简单,就是让我们判断所给图是否是一个由无向边组成的树。我们只要稍加修改一下并查集模板就可以了,一是在join(a,b)时,如果是a->b,就fa[find(a)] = find(b),否则就fa[find(b)] = find(a),这样如果是一颗无向边树,所有的结点在压缩路径之后都会指向根结点。然后在添加边的时候,要记录一下每个结点的入度情况,因为是一个有向树,只有根结点入度为0,其余的入度都为1,统计一下,然后判断一下就可以了。

AC代码

#include <iostream>
#include <algorithm>
#include <stdio.h>
using namespace std;
const int maxn = 1e6+10;

int fa[maxn],in[maxn],id[maxn],tail;

void init(){
    tail = 1;
    for(int i = 1;i<=100010;i++) {
        fa[i] = i;
        in[i] = 0;
    }
}

int find(int x){
    if(x != fa[x])
        fa[x] = find(fa[x]);
    return fa[x];
}

void join(int x,int y){
    in[y]++;
    int fx = find(x),fy = find(y);
    if(fx != fy){
        fa[fy] = fx;
    }
}

int main(){
    int x,y,kase = 1;
    while(scanf("%d %d",&x,&y)){
        bool ok = true;
        init();
        if(x == 0 && y == 0){ //特殊情况
            printf("Case %d is a tree.\n",kase++);
            continue;
        }
        if(x <0 && y<0) break;
        do{
            id[tail++] = x,id[tail++] = y;
            if(find(x) != find(y)){
                join(x,y);
            }else{
                ok = false;
            }
        }while(scanf("%d%d",&x,&y) && !(x==0 && y == 0));
        if(!ok) printf("Case %d is not a tree.\n",kase++);
        else{
            for(int i = 1;i<tail;i++) find(id[i]);//压缩路径
            int root = fa[id[1]];
            for(int i = 1;i<tail;i++) {
                if(in[id[i]]>1) ok = false;//判断入度
                if(fa[id[i]] != root) ok = false;//判断根结点是否唯一
            }
            if(!ok) printf("Case %d is not a tree.\n",kase++);
            else printf("Case %d is a tree.\n",kase++);
        }
    }
    return 0;
}