题意:给你一个有向图,第一问:增加一个点至少需要加多少边使得该点能到达其他所有点。
第二问:至少需要加多少边使得整个图变成一个强连通分量。
对于第一问就很简单了,只需要求出缩点后入度为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;
}