题意:
- taskA:
询问有从给几个学校发送任务可以使全部学校的到软件 - taskB:
询问要加入几条边可以使所有强连通分量成为一个强联通分量
思路
- tarjan 求强联通分量
- 对于taskA 显然只需记录有几个强联通分量的入度为零
- 对于taskB 应为入度为零 出度为零的强联通分量的个数较小值
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
#define mem(a) memset(a,0,sizeof(a))
#define MAX_V 110
#define MAX_E 10010
struct edge{
int to;
int next;
};
edge es[MAX_E];
int head[MAX_V],len;
int V;
int dfn[MAX_V],low[MAX_V];
int index,bcnt;
int in[MAX_V],out[MAX_V];
int belong[MAX_V];
int stk[MAX_V],top;
int instack[MAX_V];
void addedge(int from,int to)
{
es[len].to = to;
es[len].next = head[from];
head[from] = len++;
}
void tarjan(int u){
dfn[u] = low[u] = ++index;
instack[u] = 1;
stk[top++] = u;
for (int i = head[u];i != -1;i = es[i].next){
int v = es[i].to;
if (dfn[v] == -1){
tarjan(v);
if (low[u] > low[v]){
low[u] = low[v];
}
} else if (instack[v]){
if(dfn[v] < low[u]){
low[u] = dfn[v];
}
}
}
if (dfn[u] == low[u]){
bcnt++;
int v;
do {
v = stk[--top];
instack[v] = 0;
belong[v] = bcnt;
} while (v != u);
}
}
void init(){
len = top = bcnt = index = 0;
mem(stk);
mem(low);
mem(instack);
mem(in);
mem(out);
memset(dfn,-1,sizeof dfn);
memset(head,-1,sizeof head);
}
void solve(){
for (int i = 1;i<=V;i++){
if (dfn[i] == -1)
tarjan(i);
}
if (bcnt == 1){
printf("1\n0\n");
return;
}
for (int u = 1;u<=V;u++){
for (int i = head[u];i != -1;i = es[i].next){
int v = es[i].to;
if (belong[v] == belong[u]){
continue;
}
out[belong[u]]++;
in[belong[v]]++;
}
}
int a,b;
a = b = 0;
for (int i = 1;i<=bcnt;i++){
if (!in[i]){
a++;
} else if (!out[i]){
b++;
}
}
printf("%d\n",a);
printf("%d\n",max(a,b));
}
int main()
{
while(~scanf("%d",&V)){
init();
for (int u = 1;u<=V;u++){
int v;
while(scanf("%d",&v) != EOF){
if (!v) break;
addedge(u,v);
}
}
solve();
}
return 0;
}