创世纪

上帝手中有 N 种世界元素,每种元素可以限制另外1种元素,把第 i 种世界元素能够限制的那种世界元素记为 A[i]。

现在,上帝要把它们中的一部分投放到一个新的空间中去建造世界。

为了世界的和平与安宁,上帝希望所有被投放的世界元素都有至少一个没有被投放的世界元素限制它。

上帝希望知道,在此前提下,他最多可以投放多少种世界元素?

输入格式

第一行是一个整数N,表示世界元素的数目。

第二行有 N 个整数A[1], A[2], …, A[N]。A[i] 表示第 i 个世界元素能够限制的世界元素的编号。

输出格式

一个整数,表示最多可以投放的世界元素的数目。


内向树

强势断环+最大独立子集

#include<bits/stdc++.h>
#define re return
#define inc(i,l,r) for(int i=l;i<=r;++i) 
using namespace std;
template<typename T>inline void rd(T&x)
{
    char c;bool f=0;
    while((c=getchar())<'0'||c>'9')if(c=='-')f=1;
    x=c^48;
    while((c=getchar())>='0'&&c<='9')x=x*10+(c^48);
    if(f)x=-x;
}

const int maxn=1e5+5;
int k;
int n,tot,fa[maxn],hd[maxn],du[maxn],q[maxn],f[maxn][2];
int loop[maxn][2],flag;

struct node{
    int to,nt;
}e[maxn];
inline void add(int x,int y)
{
    e[++k].to=y;e[k].nt=hd[x];hd[x]=k;
    ++du[x];
}

inline int find(int x)
{
    re x==fa[x]?x:fa[x]=find(fa[x]);
}

inline void dfs(int x)
{
    f[x][0]=0;
    int con=0x3f3f3f3f*(flag!=x);
    for(int i=hd[x];i;i=e[i].nt)
    {
        int v=e[i].to;
        dfs(v);
        f[x][0]+=max(f[v][1],f[v][0]);
        con=min(con,max(f[v][1],f[v][0])-f[v][0]);
    }
    f[x][1]=f[x][0]-con+1;
    //底层边除特殊的那条除外,都不能选
}

int main()
{
//    freopen("in.txt","r",stdin);
    int x;
    rd(n);
    inc(i,1,n)
    fa[i]=i;
    inc(i,1,n)
    {
        rd(x);
        int fx=find(i),fy=find(x);
        if(fx!=fy)
        {
            add(x,i);
            fa[fx]=fy;
        }
        else
        {
            loop[++tot][0]=i;
            loop[tot][1]=x;
        }
    }
    
    int ans=0;
    int now;
    inc(i,1,tot)
    {
        dfs(loop[i][0]);
        now=max(f[loop[i][0]][1],f[loop[i][0]][0]);
        flag=loop[i][1];
        dfs(loop[i][0]);
        now=max(now,f[loop[i][0]][0]);
        ans+=now;
    }
    printf("%d",ans);
    re 0;
}
原文地址:https://www.cnblogs.com/lsyyy/p/11725106.html