題意:有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;
}