State: 160K 0MS C++ 2158B
#include <iostream>
#include <vector>
#include <cstring>
#include <cstdio>
using namespace std;
const int MAXN = 105;
vector<int> vec[MAXN];
int dfn[MAXN], low[MAXN], inS[MAXN];
int step, scc, id[MAXN], myS[MAXN], top;
//缩点建有向无环图
vector<int> sccvec[MAXN];
int vst[MAXN];
void addEdge(int u, int v)
{
vec[u].push_back(v);
}
void init()
{
top = 0;
scc = 1;
step = 0;
for(int i = 0; i < MAXN; i++)
{
vst[i] = 0;
sccvec[i].clear();
id[i] = -1;
inS[i] = 0;
dfn[i] = low[i] = -1;
vec[i].clear();
}
}
void tarjan_scc(int n)
{
dfn[n] = low[n] = ++step;
myS[top++] = n;
inS[n] = 1;
for(unsigned i = 0; i < vec[n].size(); i++)
{
int son = vec[n][i];
if(dfn[son] == -1)
{
tarjan_scc(son);
low[n] = min(low[n], low[son]);
}
else if(inS[son] == 1)
low[n] = min(low[n], dfn[son]);
}
if(dfn[n] == low[n])
{
int tmp;
do
{
tmp = myS[--top];
id[tmp] = scc;
inS[tmp] = 0;
}while(top != 0 && tmp != n);
scc++;
}
}
void deal_scc(int n, int &sol1, int &sol2)
{
int in[MAXN] = {0}, out[MAXN] = {0};
int inTree[MAXN] = {0};
for(int i = 1; i <= n; i++)
{
for(unsigned j = 0; j < vec[i].size(); j++)
{
int u = i, v = vec[i][j];
if(id[u] == id[v])
continue;
else
{
sccvec[id[u]].push_back(id[v]);
inTree[id[v]]++;
in[id[v]]++;
out[id[u]]++;
}
}
}
sol1 = 0;
for(int i = 1; i < scc; i++)
{
if(inTree[i] == 0)
sol1++;
}
//sol2
int IN = 0, OUT = 0, other = 0;
for(int i = 1; i < scc; i++)
{
if(in[i] == 0)
IN++;
if(out[i] == 0)
OUT++;
}
if(scc <= 2)
sol2 = 0;
else
sol2 = max(IN, OUT);
}
int main(void)
{
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif
int n;
while(scanf("%d", &n) == 1)
{
init();
int u, v;
for(int i = 1; i <= n; i++)
{
while(scanf("%d", &v), v)
{
addEdge(i, v);
}
}
for(int i = 1; i <= n; i++)
{
if(dfn[i] == -1)
tarjan_scc(i);
}
int sol1, sol2;
deal_scc(n, sol1, sol2);
printf("%d\n%d\n", sol1, sol2);
}
return 0;
}