URAL 1742 Team building 强联通

每个人到他认为最强的人连一条边。

缩点后,入度为0的点是最小解,强联通分量是最大解。

---

const int maxn=111100;
const int maxm=210000;
int n;
struct Node {
    int to,next;
} edges[maxm];
int head[maxn],edge;
void addedge(int u,int v) {
    edges[edge].to=v,edges[edge].next=head[u],head[u]=edge++;
}
void prepare() {
    memset(head,-1,sizeof head);
    edge=0;
}
int a[maxn];
int pre[maxn],lowlink[maxn],sccno[maxn],scc_cnt,dfs_clock;
stack<int>stk;
void dfs(int u) {
    pre[u]=lowlink[u]=++dfs_clock;
    stk.push(u);
    for (int i=head[u]; i!=-1; i=edges[i].next) {
        int v=edges[i].to;
        if (!pre[v]) {
            dfs(v);
            lowlink[u]=min(lowlink[u],lowlink[v]);
        } else if (!sccno[v]) {
            lowlink[u]=min(lowlink[u],pre[v]);
        }
    }
    if (lowlink[u]==pre[u]) {
        scc_cnt++;
        int x;
        do {
            x=stk.top();
            stk.pop();
            sccno[x]=scc_cnt;
        } while (x!=u);
    }
}
void find_scc(int n) {
    dfs_clock=scc_cnt=0;
    clr(sccno,0);
    clr(pre,0);
    while (!stk.empty()) stk.pop();
    REP_1(i,n) if (!pre[i]) dfs(i);
}
int num[maxn];
int main() {
    memset(num,0,sizeof num);
    scanf("%d",&n);
    prepare();
    for (int i=1; i<=n; i++) {
        scanf("%d",&a[i]);
        addedge(i,a[i]);
    }
    find_scc(n);
    for (int i=1; i<=n; i++) {
        if (sccno[i]!=sccno[a[i]]) {
            num[sccno[a[i]]]++;
        }
    }
    int cnt=0;
    for (int i=0; i<scc_cnt; i++) {
        if (num[i]==0) cnt++;
    }
    printf("%d %d
",cnt,scc_cnt);
    return 0;
}


---


原文地址:https://www.cnblogs.com/cyendra/p/3681516.html