拓扑排序应用——家谱树、可达性统计

有个人的家族很大,辈分关系很混乱,请你帮整理一下这种关系。

给出每个人的孩子的信息。

输出一个序列,使得每个人的孩子都比那个人后列出。

输入格式
第 1 行一个整数 n ,表示家族的人数;

接下来 n 行,第 i 行描述第 i 个人的孩子;

每行最后是 0 表示描述完毕。

每个人的编号从 1 到 n 。

输出格式
输出一个序列,使得每个人的孩子都比那个人后列出;

数据保证一定有解,如果有多解输出任意一解。

数据范围
1≤n≤100
输入样例:
5
0
4 5 1 0
1 0
5 3 0
3 0
输出样例:
2 4 5 3 1

所用数据结构为链式前向星存的边,也可以用邻接表或邻接矩阵。

#include <bits/stdc++.h>

using namespace std;
int head[1100], ans[110];
int cnt;
struct node
{
    int to, ne;
} a[1010];
int vis[111];
int n;
void add(int x, int y)
{
    cnt++;
    a[cnt].to = y;
    a[cnt].ne = head[x];
    head[x] = cnt;
}
void to_sort()
{
    int hh = -1, tt = 0;
    for (int i = 1; i <= n; i++)
        if (vis[i] == 0) ans[++hh] = i;
    while (tt <= hh)
    {
        int temp = ans[tt];
        for (int i = head[temp]; i != -1; i = a[i].ne)
        {
            int now = a[i].to;
            vis[now]--;
            if (vis[now] == 0) ans[++hh] = now;
        }
        tt++;
    }
    for (int i = 0; i <= hh; i++) cout << ans[i] << " ";
}
int main()
{
    cin >> n;
    memset(head, -1, sizeof(head));
    for (int i = 1; i <= n; i++)
    {
        int x;
        while (cin >> x && x)
        {
            add(i, x);
            vis[x]++;
        }
    }
    to_sort();

    return 0;
}

给定一张 N 个点 M 条边的有向无环图,分别统计从每个点出发能够到达的点的数量。

输入格式
第一行两个整数 N,M,接下来 M 行每行两个整数 x,y,表示从 x 到 y 的一条有向边。

输出格式
输出共 N 行,表示每个点能够到达的点的数量。

数据范围
1≤N,M≤30000
输入样例:
10 10
3 8
2 3
2 5
5 9
5 9
2 3
3 9
4 8
2 10
4 9
输出样例:
1
6
3
3
2
1
1
1
1
1

#include <bits/stdc++.h>

using namespace std;
const int N = 30010;
int head[N],ans[N],vis[N];
int cnt,n,m;
bitset<N> b[N];
struct node
{
    int to,ne;
}a[N];
void add(int x,int y)
{
    cnt++;
    a[cnt].to = y;
    a[cnt].ne = head[x];
    head[x] = cnt;
}
void to_sort()
{
    int tt = 0,hh=-1;
    for(int i=1;i<=n;i++)
    if(vis[i]==0)
    ans[++hh] = i;
    while(tt<=hh)
    {
        int temp = ans[tt];
        for(int i=head[temp];i!=-1;i=a[i].ne)
        {
            int now = a[i].to;
            vis[now]--;
            if(vis[now]==0)
            ans[++hh] = now;
        }
        tt++;
    }
    for(int i = n-1;i>=0;i--)
    {
        int x = ans[i];
        b[x][x] = 1;
        for(int i=head[x];i!=-1;i=a[i].ne)
        {
            int temp = a[i].to;
            b[x]=b[x]|b[temp];
        }
    }
    for(int i=1;i<=n;i++)
    {
        cout <<b[i].count()<<endl;
    }
  
}
int main()
{
    cin >> n>>m;
    memset(head,-1,sizeof(head));
    for(int i=1;i<=m;i++)
    {
        int x,y;
        cin >> x >>y;
        add(x,y);
        vis[y]++;
    }
    to_sort();
    
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值