洛谷P2921 Trick or Treat on the Farm 【思维 + 对图的一些操作】

版权声明:本文为博主原创文章,喜欢就点个赞吧 https://blog.csdn.net/Anxdada/article/details/82628210

传送门
题意: 给出每个编号下一个要到达的编号, 问最后每个标号可以到达的编号数量(具体可以看样例)

思路: 很明显有环的情况需要考虑, 所以实际上这是一副链环的有向的非联通图, 有自环的情况. 所以我们有先把链的情况删掉, 然后统计出每个环的大小, 然后再次累加到那些链的上面就行了. 就按照这个实现即可. 具体细节还要自己思考下…

AC Code

const int maxn = 1e5+5;
int ans[maxn], in[maxn], a[maxn];
int vis[maxn];
void bfs(int st) {
    queue<int>q; q.push(st);
    while(!q.empty()) {
        int u = q.front(); q.pop(); vis[u] = 1;
        if (--in[a[u]] == 0) q.push(a[u]);
    }
}
int cnt;
void dfs1(int u) {
    ++ cnt; vis[u] = 2;
    ans[u] = cnt;
    if (vis[a[u]]) return ;
    dfs1(a[u]);
    ans[u] = cnt;
}
int dfs2(int u) {
    ans[u] = 1; vis[u] = 2;
    if (vis[a[u]] == 2) return ans[u] += ans[a[u]];
    ans[u] += dfs2(a[u]);
    return ans[u];
}
void solve() {
    int n; scanf("%d", &n);
    for (int i = 1 ; i <= n ; i ++) {
        scanf("%d", a+i);
        ++ in[a[i]];
    }
    for (int i = 1 ; i <= n ; i ++) {
        if (!in[i] && !vis[i]) bfs(i);  // 删链
    }
    for (int i = 1 ; i <= n ; i ++) {
        if (!vis[i]) cnt = 0, dfs1(i);  // 统计环的大小
    }
    for (int i = 1 ; i <= n ; i ++) {
        if (!ans[i]) dfs2(i);   // 累加到链上面
    }
    for (int i = 1 ; i <= n ; i ++) {
        printf("%d\n", ans[i]);
    }
}

猜你喜欢

转载自blog.csdn.net/Anxdada/article/details/82628210
今日推荐