PAT Advanced 1004. Counting Leaves (30) (C语言实现)

我的PAT系列文章更新重心已移至Github,欢迎来看PAT题解的小伙伴请到Github Pages浏览最新内容。此处文章目前已更新至与Github Pages同步。欢迎star我的repo

题目

A family hierarchy is usually presented by a pedigree tree. Your job is to
count those family members who have no child.

Input Specification:

Each input file contains one test case. Each case starts with a line
containing 0<N<100 , the number of nodes in a tree, and M ( <N ), the
number of non-leaf nodes. Then M lines follow, each in the format:

ID K ID[1] ID[2] ... ID[K]

where ID is a two-digit number representing a given non-leaf node, K is
the number of its children, followed by a sequence of two-digit ID's of its
children. For the sake of simplicity, let us fix the root ID to be 01.

The input ends with N being 0. That case must NOT be processed.

Output Specification:

For each test case, you are supposed to count those family members who have no
child for every seniority level starting from the root. The numbers must
be printed in a line, separated by a space, and there must be no extra space
at the end of each line.

The sample case represents a tree with only 2 nodes, where 01 is the root
and 02 is its only child. Hence on the root 01 level, there is 0 leaf
node; and on the next level, there is 1 leaf node. Then we should output 0 1 in a line.

Sample Input:

2 1
01 1 02

Sample Output:

0 1

思路

虽然是30分的题,但是好像比1003还简单。

同样使用了邻接链表(adjacent list),数据结构如下:

  • Member(Vertex):表示一个家庭成员,我使用了两个结构成员:
  • level,表示这个人在家谱中的辈分,最高的辈分是0,辈分越低,level越大
  • child,指向Child结构变量,即链表的第一个节点
  • Child(Edge):表示亲子关系,也使用了两个结构成员:
  • ID,表示这个孩子的ID
  • iter,指向相同父母的下一个孩子Child变量

读取数据,建立邻接链表。初始化01节点的level为0,其他level为INF。

然后按level从0开始,依次遍历所有Member,找出相应辈分的家庭成员。这时分两种情况:这个成员没有孩子,那么需要进行计数;这个成员有孩子,那么需要更新他们的level值为这个成员的level+1,以便下一次遍历时找到他们。

使用一个标记表明何时不需再遍历,我用的是记录人数,当之前所有level的人数已经是总人数,那么说明已全部遍历,此时退出循环。

代码

最新代码@github,欢迎交流

#include <stdio.h>

#define MAX 999

typedef struct Member *Member;
typedef struct Child *Child;

struct Member{
    int level;
    Child child;
};

struct Child{
    int ID;
    Child iter;
};

int main()
{
    int N, M, ID, cID, K;
    struct Member nodes[100];
    struct Child children[100];

    /* Read data and initiate a adjacent list */
    scanf("%d %d", &N, &M);
    for(int i = 1; i <= N; i++)
    {
        nodes[i].level = MAX;
        nodes[i].child = NULL;
    }
    nodes[1].level = 0;         /* root node at level 0 */
    for(int i = 0, k = 0; i < M; i++)
    {
        scanf("%d %d", &ID, &K);
        for(; K--; k++)
        {
            scanf("%d", &cID);
            children[k].ID = cID;
            children[k].iter = nodes[ID].child;
            nodes[ID].child = &children[k];
        }
    }

    /* For every level, find leaf nodes */
    int n = N, count;
    for(int level = 0; n; level++)
    {
        count = 0;
        for(int i = 1; i <= N; i++) if(nodes[i].level == level)
        {
            n--;
            if(nodes[i].child == NULL)
                count++;
            /* set the children to next level */
            for(Child c = nodes[i].child; c; c = c->iter)
                nodes[c->ID].level = level + 1;
        }

        printf("%d%c", count, n ? ' ' : '\0');
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值