1 条题解

  • 0
    @ 2025-8-24 22:20:36

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Randyhoads
    AFO.

    搬运于2025-08-24 22:20:36,当前版本为作者最后更新于2020-10-23 15:23:15,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    更好的体验?

    贪心

    把指认的关系当做边连边,把坏蛋当做染成1,好人当做染成0

    由于坏蛋不能连坏蛋,与1相连的点一定为0

    假如是一条链的话,显然交叉染色,从链尾开始染更优

    把链扩展成树,发现每次把入度为0的点染成1一定最优

    但是实际上有可能出现环

    考虑为环的情况,如果环上的点都没有限制,显然随便选一个点染成0,这个点两边染色就没有限制了,就断成链了

    考虑环上的点有限制的情况,即为基环树的情况

    还是从入度为0的点开始染,环上有点被确定染成了0那么这个环显然就被断成链了,就按找链的方式贪心即可

    所以可以设计出这样一个贪心算法

    每次把入度为0且没有确定下来的点染成1,这样最后剩下的一定是几个独立的环

    每次随便选环上一点染成0,把环断成链即可

    #include<bits/stdc++.h>
    
    using namespace std;
    
    inline int read()
    {
        int f = 1,x = 0;
        char ch;
        do
        {
            ch = getchar();
            if(ch == '-') f = -1;
        }while(ch < '0'||ch > '9');
        do
        {
            x = (x<<3) + (x<<1) + ch - '0';
            ch = getchar();
        }while(ch >= '0'&&ch <= '9');
        return f*x;
    }
    
    const int MAXN = 5e5 + 10;
    
    int n;
    int a[MAXN];
    int deg[MAXN]; 
    bool vis[MAXN];
    int ans;
    
    inline void dfs(int x,int col)
    {
        if(vis[x]) return;
        vis[x] = 1; 
        ans += col;
        deg[a[x]]--;
        if((!deg[a[x]])||col == 1) dfs(a[x],col^1);
    }
    
    int main()
    {
        n = read();
        for(int i=1;i<=n;i++) a[i] = read(),deg[a[i]]++;
        for(int i=1;i<=n;i++) if(!deg[i]) dfs(i,1);
        for(int i=1;i<=n;i++) if(!vis[i]) dfs(i,0);
        cout << ans << endl;
    }
    
    
    • 1

    信息

    ID
    5448
    时间
    1000ms
    内存
    32MiB
    难度
    4
    标签
    递交数
    0
    已通过
    0
    上传者