题目描述
一些学校连入一个电脑网络。那些学校已订立了协议:每个学校都会给其它的一些学校分发软件(称作“接受学校”)。注意即使 BB 在 AA 学校的分发列表中,AA 也不一定在 BB 学校的列表中。
你要写一个程序计算,根据协议,为了让网络中所有的学校都用上新软件,必须接受新软件副本的最少学校数目(子任务 A)。更进一步,我们想要确定通过给任意一个学校发送新软件,这个软件就会分发到网络中的所有学校。为了完成这个任务,我们可能必须扩展接收学校列表,使其加入新成员。计算最少需要增加几个扩展,使得不论我们给哪个学校发送新软件,它都会到达其余所有的学校(子任务 B)。一个扩展就是在一个学校的接收学校列表中引入一个新成员。
思路
子任务A:targan之后把图转化成DAG,然后统计图中入度为0的点的个数,这个很好理解,对于入度为0的点是一定需要分发软件的。
子任务B:
- 如果连通分量只有一个:答案是1,0。
- 否则,我们的任务就是把多个独立的连通分量给连接起来,并且形成一个环。
具体怎么来做呢?其实连接的方法有很多种,但是我们需要得到新增加的边的数量最小的方案,从下图可以看出
简单的分析下:对于图中所有入读为0的点,我们必须增加一条连接这个点的边,对于途中所有出度为0的边,我们必须添加一条边让它连接到别的点,那么自然而然地我们就是连接处度为0和入度为0地点了,那么边的数量很明显就是
m
a
x
(
i
n
D
0
,
o
u
t
D
0
)
)
max(inD_0, outD_0))
max(inD0,outD0)),其中
i
n
D
0
inD_0
inD0代表入度为0地点地个数,
o
u
t
D
0
outD_0
outD0代表出度为0地点地个数。
代码很好写,基本就是套模板。
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int maxn = 110;
struct edge{
int from, to, nxt;
} edges[100010];
int tot, head[maxn];
void add_edge(int u, int v){
edges[tot] = edge{u, v, head[u]};
head[u] = tot++;
}
int n, tp, idx;
int dfn[maxn], low[maxn], st[maxn], vis[maxn], inD[maxn], outD[maxn], scc[maxn];
void tarjan(int now) {
dfn[now] = low[now] = ++idx;
st[tp++] = now; vis[now] = 1;
for (int i = head[now]; ~i; i = edges[i].nxt) {
int to = edges[i].to;
if (!dfn[to]) {
tarjan(to);
low[now] = min(low[now], low[to]);
} else if (vis[to])
low[now] = min(low[now], dfn[to]);
}
if (dfn[now] == low[now]) {
while (1) {
int y = st[--tp];
scc[y] = now;
vis[y] = 0;
if (now == y) break;
}
}
}
int main() {
memset(head, -1, sizeof head);
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
int v;
while (1) {
cin >> v; if (v==0) break;
add_edge(i, v);
}
}
for (int i = 1; i <= n; i++)
if (!dfn[i]) tarjan(i);
for (int i = 0; i < tot; i++) {
int u = scc[edges[i].from];
int v = scc[edges[i].to];
if (u != v) {
inD[v]++;
outD[u]++;
}
}
int ans1=0, ans2=0, cnt=0;
for (int i = 1; i <= n; i++) {
if (scc[i] != i) continue;
if(inD[i] == 0) ans1++;
if(outD[i] == 0) ans2++;
cnt++;
}
cout << ans1 << endl;
if (cnt != 1)cout << max(ans1, ans2) << endl;
else cout << "0" << endl;
return 0;
}