题意:有n所学校需要信息交流,每个学校有一个信息下发列表,表示这个学校可以把信息传递给列表里的学校,问开始至少需要几个学校发出信息才能使所以学校都接收信息,如果不能完成问最少要往信息列表里添加多少条信息
第一问就是缩点然后求入度为0的点的个数, 第二问相当于求补多少条边能使整个图联通, 补的边数是入度为0和出度为0的点数中大的那个(挺好理解的就不解释了)
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
const int mx = 105;
int dfn[mx], low[mx], stack[mx], color[mx], in[mx], out[mx], n, cnt, top, sum;
bool vis[mx];
vector <int> G[mx];
void init()
{
cnt = sum = top = 0;
memset(vis, false, sizeof(vis));
memset(dfn, 0, sizeof(dfn));
memset(low, 0, sizeof(low));
memset(in, 0, sizeof(in));
memset(out, 0, sizeof(out));
for (int i = 0; i < mx; i++)
G[i].clear();
}
void tarjan(int u)
{
low[u] = dfn[u] = ++cnt;
stack[++top] = u;
vis[u] = true;
int v, len = G[u].size();
for (int i = 0; i < len; i++)
{
v = G[u][i];
if (!dfn[v])
{
tarjan(v);
low[u] = min(low[u], low[v]);
}
else if (vis[v])
low[u] = min(low[u], dfn[v]);
}
if (low[u] == dfn[u])
{
color[u] = ++sum;
//printf("sum = %d\n",sum);
while (stack[top] != u)
{
//printf("top = %d\n",stack[top]);
vis[stack[top]] = false;
color[stack[top]] = sum;
top--;
}
//printf("top = %d\n",u);
vis[u] = false;
top--;
}
}
void solve()
{
for (int i = 1; i <= n; i++)
if (!dfn[i]) tarjan(i);
int v;
for (int i = 1; i <= n; i++)
{
int len = G[i].size();
for (int j = 0; j < len; j++)
{
v = G[i][j];
if (color[i] != color[v])
{
out[color[i]]++;
in[color[v]]++;
}
}
}
}
int main()
{
while (scanf("%d",&n) != EOF)
{
init();
for (int i = 1; i <= n; i++)
{
int x;
while (scanf("%d",&x) == 1 && x != 0)
G[i].push_back(x);
}
solve();
if (sum == 1)
{
printf("1\n0\n");
continue;
}
int ans1 = 0, ans2 = 0;
for (int i = 1; i <= sum; i++)
{
if (in[i] == 0) ans1++;
if (out[i] == 0) ans2++;
}
printf("%d\n%d\n",ans1,max(ans1,ans2));
}
return 0;
}