|
这道题有两问
第一问很简单,先tarjin缩一下点,然后找出所有入度为0的点,那么这些点是必须要副本的,其他的点一定可以有这些点到达,所以答案就是所有入度为0的点
第二问,有一个小结论,就是一个有向图我们只需要最多连max(入度为0的点的个数,初度为0的点的个数)条边,那么个图就可以成为强连通的,即从任意一个点可以到达另外所有点,但当只有一个强连通分量的时候要输出0而不是1
#include <bits/stdc++.h> #define ll long long using namespace std; inline int read(){ int x=0;int f=1;char ch=getchar(); while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} return x*f; } const int MAXN=1e4+10; namespace zhangenming{ struct node{ int x,y,next; }e[MAXN]; int linkk[MAXN],len=0,n; inline void insert(int xx,int yy){ e[++len].y=yy;e[len].x=xx;e[len].next=linkk[xx];linkk[xx]=len; } void init(){ n=read(); for(int i=1;i<=n;i++){ int xx=read(); while(xx){ insert(i,xx); xx=read(); } } } int vis[MAXN],stark[MAXN],ine[MAXN],cntt[MAXN]={},tot=0,top=0,cnt[MAXN]={},dfn[MAXN]={},low[MAXN],dfs_clock=0; inline void tarjin(int st){ //cout<<st<<endl; dfn[st]=low[st]=++dfs_clock;vis[st]=1; stark[++top]=st; for(int i=linkk[st];i;i=e[i].next){ if(!dfn[e[i].y]){ //cout<<e[i].y<<endl; tarjin(e[i].y); low[st]=min(low[st],low[e[i].y]); } else if(vis[e[i].y]) low[st]=min(low[st],dfn[e[i].y]); } if(low[st]==dfn[st]){ tot++; int k; do{ k=stark[top--]; ine[k]=tot; vis[k]=0; }while(k!=st); } } void solve(){ memset(vis,0,sizeof(vis)); for(int i=1;i<=n;i++){ if(!ine[i]) tarjin(i); } for(int i=1;i<=len;i++){ int xx=e[i].x;int yy=e[i].y; if(ine[xx]==ine[yy]) continue; cnt[ine[yy]]++; cntt[ine[xx]]++; } int sum1=0;int sum2=0; for(int i=1;i<=tot;i++){ if(!cnt[i]) sum1++; if(!cntt[i]) sum2++; } cout<<sum1<<endl; if(tot!=1) cout<<max(sum1,sum2)<<endl; else cout<<0<<endl; } } int main(){ using namespace zhangenming; init(); solve(); return 0; }