题目地址


简述:

  • 缩点后进行条件判定.

易错点:

  • 首先,可以进行缩点.
  • 子任务1:缩点后入度为零的强连通分量必须要有新软件.
  • 子任务2:要求加边后形成一个强连通图。可以考虑到缩点后的DAG上每个点都必须同时具有入度和出度,就可以将没有入度的点的数量记为p,没有出度的点的数量记为q;由于没有出度的点可以直接连接没有入度的点,答案即为max(p,q).

#include<cstdio>
#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
const int MAXN=1000010,MAXM=1000010;
struct firstEdge1{
    int from,to,nxt;
}firstEdge[MAXM];
int firstHead[MAXN],firstEdgeCnt=0;
void addFirstEdge(int u,int v){
    firstEdge[++firstEdgeCnt].from=u;
    firstEdge[firstEdgeCnt].to=v;
    firstEdge[firstEdgeCnt].nxt=firstHead[u];
    firstHead[u]=firstEdgeCnt;
}
int dfn[MAXN],low[MAXN],dfnCnt=0;
bool inc[MAXN];
int stck[MAXN],c[MAXN],top=0;
int sccCnt=0;
vector<int> sccVec[MAXN];
void tarjan(int x){
    low[x]=dfn[x]=++dfnCnt;
    inc[x]=1;
    stck[++top]=x;
    for(int i=firstHead[x];i;i=firstEdge[i].nxt){
        int v=firstEdge[i].to;
        if(!dfn[v]){ 
            tarjan(v);
            low[x]=min(low[x],low[v]);
        }else if(inc[v])low[x]=min(low[x],dfn[v]);
    }
    if(dfn[x]==low[x]){
        int y;sccCnt++;
        do{
            y=stck[top--];
            inc[y]=0;
            c[y]=sccCnt;
            sccVec[sccCnt].push_back(y);
        }while(x!=y);
    }
}
struct SecondEdge{
    int from,to,nxt;
}secondEdge[MAXM];
int secondHead[MAXN],secondEdgeCnt=0;
void addSecondEdge(int u,int v){
    secondEdge[++secondEdgeCnt].from=u;
    secondEdge[secondEdgeCnt].to=v;
    secondEdge[secondEdgeCnt].nxt=secondHead[secondEdgeCnt];
    secondHead[u]=secondEdgeCnt;
}
int rd[MAXN],cd[MAXN];
int main(){
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        int tmp;
        while(true){
            scanf("%d",&tmp);
            if(tmp==0)break;
            addFirstEdge(i,tmp);
        }
    }
    for(int i=1;i<=n;i++)
        if(!low[i])tarjan(i);
    for(int i=1;i<=firstEdgeCnt;i++){
        int u=firstEdge[i].from;
        int v=firstEdge[i].to;
        if(c[u]!=c[v]){
            addSecondEdge(c[u],c[v]);
            rd[c[v]]++;
            cd[c[u]]++;
        }
    }
    int p=0,q=0; 
    for(int i=1;i<=sccCnt;i++){
        if(rd[i]==0)p++;
        if(cd[i]==0)q++;
    } 
    cout<<p<<endl;
    if(sccCnt==1)cout<<"0"<<endl;
    else cout<<max(p,q)<<endl;
    return 0;
}