大意:
第一问:最小的数量需要收到复制软件从而使得所有学校都有软件。(You are to write a program that computes the minimal number of schools that must receive a copy of the new software)
第二问:建立最小数量的“路”,使得任意的学校两两可达。
思路:第一问,“缩点”之后判断入度为0的强连通分量。第二问,与Hdu 2767很相似,求连接最小的路使得图变为强连通图。判断入度0与出度为0的最大值。
CODE:
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
using
namespace std;
#define MAXN 50010
#define MAXM 100010
struct Edge
{
int v, next;
}edge[MAXM];
int first[MAXN], stack[MAXN], ins[MAXN], dfn[MAXN], low[MAXN];
int belong[MAXM];
int ind[MAXN], outd[MAXN];
int n, m;
int cnt;
int scnt, top, tot;
void init()
{
cnt =
0;
scnt = top = tot =
0;
memset(dfn,
0,
sizeof(dfn));
memset(first, -
1,
sizeof(first));
memset(ins,
0,
sizeof(ins));
memset(ind,
0,
sizeof(ind));
memset(outd,
0,
sizeof(outd));
}
void read_graph(
int u,
int v)
{
edge[cnt].v = v;
edge[cnt].next = first[u];
first[u] = cnt++;
}
void dfs(
int u)
{
int v;
dfn[u] = low[u] = ++tot;
ins[u] =
1;
stack[top++] = u;
for(
int e = first[u]; e != -
1; e = edge[e].next)
{
v = edge[e].v;
if(!dfn[v])
{
dfs(v);
low[u] = min(low[u], low[v]);
}
else
if(ins[v])
{
low[u] = min(low[u], dfn[v]);
}
}
if(dfn[u] == low[u])
{
scnt++;
do
{
v = stack[--top];
belong[v] = scnt;
ins[v] =
0;
}
while(v != u);
}
}
void Tarjan()
{
for(
int v =
1; v <= n; v++)
if(!dfn[v])
dfs(v);
}
void solve()
{
Tarjan();
//
Tarjan
if(scnt ==
1) { printf(
"
1\n0\n
");
return ;}
//
本身是强连通图
for(
int u =
1; u <= n; u++)
{
for(
int e = first[u]; e != -
1; e = edge[e].next)
{
int v = edge[e].v;
if(belong[u] != belong[v]) ind[belong[v]]++, outd[belong[u]]++;
}
}
int max1 =
0, max2 =
0, ans =
0;
for(
int i =
1; i <= scnt; i++)
{
if(!outd[i]) max1++;
if(!ind[i]) max2++;
}
printf(
"
%d\n
", max2);
printf(
"
%d\n
", max1 > max2 ? max1:max2);
}
int main()
{
while(~scanf(
"
%d
", &n))
{
init();
for(
int u =
1; u <= n; u++)
{
int v;
while(scanf(
"
%d
", &v) && v)
{
read_graph(u, v);
}
}
solve();
}
return
0;
}