有 N 个公司,从每个公司都能单向地向另外一个公司分享最新商业信息,因为他们之间有着某种合作,你需要解决两个问题:
- 现在有一个最新的商业信息,至少需要告诉多少个公司,使得所有的公司最终都能得到该信息。
- 在原有基础上,至少需要再让多少对公司建立这种合作,使任意一个公司获得某个最新商业信息后,经过若干次分享,所有的公司最终都能得到该信息。
输入格式
第一行输入一个整数 N (1≤N≤100)。
接下来 N行,每行若干个整数,表示第 ii 个公司可以向哪些公司分享信息,以 0 结束。
输出格式
输出共两行,每行一个整数,分别表示问题 1 和问题 2 的答案。
样例输入
6 0 6 0 2 0 2 0 3 1 0 0
样例输出
2 2
分析:先缩点,第一小问就是求有多少点的入度为0,第二小问怎么求呢?
显然要加边使原图变成一个强联通分量,一定要让图中的所有点的出度和入度都为0,每次我们可以连一条边从出度为0的到入度为0的,但是可能出度入度为0的点数量不相等,取个max就好了.
#include <cstdio> #include <queue> #include <cstring> #include <iostream> #include <algorithm> #include <stack> using namespace std; int n, ru[110], chu[110], head[110], nextt[10000], to[10000], tot = 1, scc[110], num, dfs_clock, pre[110], low[110],map[110][110]; int ru1[110], chu1[110]; stack<int> s; void add(int x, int y) { to[tot] = y; nextt[tot] = head[x]; head[x] = tot++; } void tarjan(int u) { pre[u] = low[u] = ++dfs_clock; s.push(u); for (int i = head[u]; i; i = nextt[i]) { int v = to[i]; if (!pre[v]) { tarjan(v); low[u] = min(low[u], low[v]); } else if (!scc[v]) low[u] = min(low[u], pre[v]); } if (low[u] == pre[u]) { num++; while (1) { int t = s.top(); s.pop(); scc[t] = num; if (t == u) break; } } } void lianbian(int x) { for (int i = head[x]; i; i = nextt[i]) { int v = to[i]; if (scc[x] != scc[v] && !map[scc[x]][scc[v]]) { map[scc[x]][scc[v]] = 1; chu1[scc[x]]++; ru1[scc[v]]++; } } } int main() { scanf("%d", &n); for (int i = 1; i <= n; i++) { int x; while (scanf("%d", &x) && x != 0) { add(i, x); ru[x]++; chu[i]++; } } for (int i = 1; i <= n; i++) if (!scc[i]) tarjan(i); for (int i = 1; i <= n; i++) lianbian(i); int ans = 0,rucnt = 0,chucnt = 0; for (int i = 1; i <= num; i++) { if (!ru1[i]) ans++; } printf("%d ", ans); //printf("%d ", num); int cr = 0, cc = 0; for (int i = 1; i <= n; i++) { if (chu[i] == 0) cc++; if (ru[i] == 0) cr++; } printf("%d", max(cc, cr)); return 0; }