并查集——poj1308(并查集延伸)
题目链接:Is It A Tree?
题意:给你一系列形如u v的点对(u v代表一条由u指向v的有向边),请问由给你的点构成的图是不是一棵树?
树的特征:①每个节点(除了根结点)只有一个入度;②只有一个根结点。
题解:用并查集合并点,对于一条边,如果连接的两点已经在同一并查集内,则可以直接判否。合并时按边的方向记录点的入度,如果某个点入度大于1也就是某个点有多个父亲节点,则说明不是树。合并时顺便记录合并总次数,最后合并点数-1次则是树。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | #include <stdio.h> #include <memory.h> const int MAX_SIZE = 105; int parent[MAX_SIZE]; bool flag[MAX_SIZE]; void make_set(){ //初始化 for ( int x = 1; x < MAX_SIZE; x ++){ parent[x] = x; flag[x] = false ; } } int find_set( int x){ //寻找根节点,带路径压缩 if (x != parent[x]) parent[x] = find_set(parent[x]); return parent[x]; } void union_set( int x, int y){ //合并 x = find_set(x); y = find_set(y); if (x == y) return ; parent[y] = x; } bool single_root( int n){ //判断是不是只有一个根,条件(1) int i = 1; while (i <= n && !flag[i]){ ++i; } int root = find_set(i); while (i <= n){ if (flag[i] && find_set(i) != root){ return false ; } ++i; } return true ; } int main(){ int x, y; bool is_tree = true ; int range = 0; int idx = 1; make_set(); while ( scanf ( "%d %d" , &x, &y) != EOF){ if (x < 0 || y < 0){ break ; } if (x == 0 || y == 0){ if (is_tree && single_root(range)){ printf ( "Case %d is a tree.\n" , idx++); } else { printf ( "Case %d is not a tree.\n" , idx++); } is_tree = true ; range = 0; make_set(); continue ; } if (!is_tree){ continue ; } range = x > range ? x : range; range = y > range ? y : range; flag[x] = flag[y] = true ; if (find_set(x) == find_set(y)){ //如果两者属于一个集合(也就是有共同祖先),并且两者还有父子关系,那么无法形成树,条件2 is_tree = false ; } union_set(x, y); } return 0; } |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步