You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

163 lines
4.4 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package class_2022_03_1_week;
// 强连通分量练习题目
// N个学校之间有单向的网络每个学校得到一套软件后可以通过单向网络向周边的学校传输
// 问题1初始至少需要向多少个学校发放软件使得网络内所有的学校最终都能得到软件
// 问题2至少需要添加几条传输线路(边),使任意向一个学校发放软件后
// 经过若干次传送,网络内所有的学校最终都能得到软件
// 2 <= N <= 1000
// 从题意中抽象出的算法模型, 给定一个有向图,求:
// 1) 至少要选几个顶点,才能做到从这些顶点出发,可以到达全部顶点
// 2) 至少要加多少条边,才能使得从任何一个顶点出发,都能到达全部顶点
// 测试链接 : http://poj.org/problem?id=1236
// 注册一下 -> 页面上点击"submit" -> 语言选择java
// 然后把如下代码粘贴进去, 把主类名改成"Main", 可以直接通过
// 请同学们务必参考如下代码中关于输入、输出的处理
// 这是输入输出处理效率很高的写法
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
import java.util.ArrayList;
public class Code02_NetworkOfSchools {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StreamTokenizer in = new StreamTokenizer(br);
PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
while (in.nextToken() != StreamTokenizer.TT_EOF) {
int n = (int) in.nval;
ArrayList<ArrayList<Integer>> edges = new ArrayList<ArrayList<Integer>>();
for (int i = 0; i <= n; i++) {
edges.add(new ArrayList<Integer>());
}
for (int from = 1; from <= n; from++) {
do {
in.nextToken();
int to = (int) in.nval;
if (to == 0) {
break;
} else {
edges.get(from).add(to);
}
} while (true);
}
StronglyConnectedComponents scc = new StronglyConnectedComponents(edges);
int sccn = scc.getSccn();
int[] inDegrees = new int[sccn + 1];
int[] outDegrees = new int[sccn + 1];
ArrayList<ArrayList<Integer>> dag = scc.getShortGraph();
for (int i = 1; i <= sccn; i++) {
for (int j : dag.get(i)) {
outDegrees[i]++;
inDegrees[j]++;
}
}
int zeroIn = 0;
int zeroOut = 0;
for (int i = 1; i <= sccn; i++) {
if (inDegrees[i] == 0) {
zeroIn++;
}
if (outDegrees[i] == 0) {
zeroOut++;
}
}
out.println(zeroIn);
out.println(sccn == 1 ? 0 : Math.max(zeroIn, zeroOut));
out.flush();
}
}
public static class StronglyConnectedComponents {
public ArrayList<ArrayList<Integer>> nexts;
public int n;
public int[] stack;
public int stackSize;
public int[] dfn;
public int[] low;
public int cnt;
public int[] scc;
public int sccn;
// 请保证点的编号从1开始不从0开始
// 注意:
// 如果edges里有0、1、2...n这些点那么容器edges的大小为n+1
// 但是0点是弃而不用的所以1..n才是有效的点所以有效大小是n
public StronglyConnectedComponents(ArrayList<ArrayList<Integer>> edges) {
nexts = edges;
init();
scc();
}
private void init() {
n = nexts.size();
stack = new int[n];
stackSize = 0;
dfn = new int[n];
low = new int[n];
cnt = 0;
scc = new int[n];
sccn = 0;
n--;
}
private void scc() {
for (int i = 1; i <= n; i++) {
if (dfn[i] == 0) {
tarjan(i);
}
}
}
private void tarjan(int p) {
low[p] = dfn[p] = ++cnt;
stack[stackSize++] = p;
for (int q : nexts.get(p)) {
if (dfn[q] == 0) {
tarjan(q);
}
if (scc[q] == 0) {
low[p] = Math.min(low[p], low[q]);
}
}
if (low[p] == dfn[p]) {
sccn++;
int top = 0;
do {
top = stack[--stackSize];
scc[top] = sccn;
} while (top != p);
}
}
public int[] getScc() {
return scc;
}
public int getSccn() {
return sccn;
}
public ArrayList<ArrayList<Integer>> getShortGraph() {
ArrayList<ArrayList<Integer>> shortGraph = new ArrayList<ArrayList<Integer>>();
for (int i = 0; i <= sccn; i++) {
shortGraph.add(new ArrayList<Integer>());
}
for (int u = 1; u <= n; u++) {
for (int v : nexts.get(u)) {
if (scc[u] != scc[v]) {
shortGraph.get(scc[u]).add(scc[v]);
}
}
}
return shortGraph;
}
}
}