先将图用tarjan缩点,形成无环图。然后求出其中入度为0和出度为0的点的个数ans1和ans2。
然后根据题意,入度为0的点需要添加一条边,所以第一问的结果就是ans1。这里的点都是图
的缩点。第二问取ans1和ans2大的那个。因为我们先将入度为0的点和出度为0的点连接是最
省的,剩下有点的话也得连接,所以是两者的最大值。
http://hi.baidu.com/scameeling/item/b135831094ec756771d5e815
强连通分量tarjan的介绍
/*Accepted 192K 0MS C++ 2109B 2012-07-30 10:53:03*/ #include<cstdio> #include<cstring> #include<cstdlib> const int MAXN = 1 << 7; const int MAXM = MAXN * MAXN; int dfn[MAXN], s[MAXN], color[MAXN], low[MAXN], ins[MAXN], indgr[MAXN], outdgr[MAXN]; int first[MAXN], next[MAXM], v[MAXM], cnt, top, col, e, ans1, ans2, N; void tarjan(int cur) { int i; dfn[cur] = low[cur] = ++ cnt; s[top ++] = cur, ins[cur] = 1; for(i = first[cur]; i != -1; i = next[i]) { if(!dfn[v[i]]) { tarjan(v[i]); if(low[v[i]] < low[cur]) low[cur] = low[v[i]]; } else if(dfn[v[i]] < low[cur] && ins[v[i]]) low[cur] = dfn[v[i]]; } if(low[cur] == dfn[cur]) { ++ col; for(s[top] = -1; s[top] != cur; ) color[s[-- top]] = col, ins[s[top]] = 0; } } void cal() { int i, j, zeroin, zeroout; cnt = top = col = 0; memset(ins, 0, sizeof ins); memset(dfn, 0, sizeof dfn); for(i = 1; i <= N; i ++) if(!dfn[i]) tarjan(i); zeroin = zeroout = 0; for(i = 1; i <= N; i ++) for(j = first[i]; j != -1; j = next[j]) if(color[i] != color[v[j]]) ++ outdgr[color[i]], ++ indgr[color[v[j]]]; for(i = 1; i <= col; i ++) { if(indgr[i] == 0) ++ zeroin; if(outdgr[i] == 0) ++ zeroout; } if( col == 1) { ans1 = 1; ans2 = 0; } else { ans1 = zeroin; ans2 = zeroin > zeroout ? zeroin : zeroout; } } void addedge(int x, int y) { v[e] = y; next[e] = first[x], first[x] = e ++; } void ReadGraph() { int i, j; e = 0; memset(first, -1, sizeof first); for(i = 1; i <= N; i ++) { for(;;) { scanf("%d", &j); if(0 == j) break; addedge(i, j); } } } int main() { while(scanf("%d", &N) == 1) { ReadGraph(); cal(); printf("%d\n%d\n", ans1, ans2); } return 0; }