题意:给你一个有向图,第一问:增加一个点至少需要加多少边使得该点能到达其他所有点。
第二问:至少需要加多少边使得整个图变成一个强连通分量。
对于第一问就很简单了,只需要求出缩点后入度为0的点的个数,对于第二问的话,需要求出缩点后入度为0的个数和出度为0的个数,较大值为答案。
比如0出度大于0入度,这样把所有0出度的连到不为该节点祖先的其他子树的0入度节点上,画个图应该很明白。
第一道强连通,很多细节刚开始出错了,现在印象很深刻了~
#include <stdio.h> #include <string.h> const int maxn = 111; const int maxm = 111*111; struct EDGE{ int to, vis, next; }edge[maxm]; int head[maxn], belo[maxn], low[maxn], dfn[maxn], st[maxn], rudu[maxn], chudu[maxn], ins[maxn]; int E, time, top, type, stot; void newedge(int u, int to) { edge[E].to = to; edge[E].vis = 0; edge[E].next = head[u]; head[u] = E++; } void init() { memset(head, -1, sizeof(head)); memset(dfn, 0, sizeof(dfn)); memset(belo, 0, sizeof(belo)); memset(rudu, 0, sizeof(rudu)); memset(chudu, 0, sizeof(chudu)); memset(ins, 0, sizeof(ins)); E = time = top = type = 0; } int min(int a, int b) { return a > b ? b : a; } int max(int a, int b) { return a > b ? a : b; } void dfs(int u) { dfn[u] = low[u] = ++time; st[++top] = u; ins[u] = 1; for(int i = head[u];i != -1;i = edge[i].next) { if(edge[i].vis) continue; edge[i].vis = 1; int to = edge[i].to; if(!dfn[to]) { dfs(to); low[u] = min(low[u], low[to]); } else if(ins[to]) { low[u] = min(low[u], low[to]); } } if(low[u] == dfn[u]) { type++; int to; do { to = st[top--]; belo[to] = type; ins[to] = 0; } while(to != u); } } void DFS(int u) { for(int i = head[u];i != -1;i = edge[i].next) { if(!edge[i].vis) continue; edge[i].vis = 0; int to = edge[i].to; DFS(to); if(belo[to] != belo[u]) { chudu[belo[u]]++; rudu[belo[to]]++; } } } int main() { init(); int i, n, to, u; scanf("%d", &n); for(i = 1;i <= n; i++) { while(scanf("%d", &to) && to) { newedge(i, to); } } for(i = 1;i <= n ;i++) if(!dfn[i]) dfs(i); if(type == 1) { printf("1\n0\n"); return 0; } for(i = 1;i <= n; i++) DFS(i); int ans1 = 0, ans2 = 0; for(i = 1;i <= type; i++) { if(rudu[i] == 0) ans1++; if(chudu[i] == 0) ans2++; } ans2 = max(ans1, ans2); printf("%d\n%d\n", ans1, ans2); return 0; }