思路
任务1:要让每个学校都有新软件用,缩点后求入度为0的结点。
任务2:连接入度为0的结点和出度为0的结点,求入度为0的结点个数与出度为0的结点个数的最大值。
特判:当此图为强连通图时,需要投放一个零件,支援关系为0。
关于任务2的图形解释:
缩点后的关系
需要建立的关系
如果还有一个强连通分量,此时需要更改原有的连接关系。
综上,将入度为0的点和出度为0的点两两连接,求一个入度为0和出度为0的最大值。
AC代码
/**
缩点 + 统计入度为0的点有多少个
*/
#include<cstdio>
#include<iostream>
#include<stack>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
#define IOS ios::sync_with_stdio(false)
const int maxn = 200 + 5;
// dfn为时间戳数组,low代表最小时间戳数组,color对一个强连通分量染同色,all一个强连通分量的个数。
int dfn[maxn], low[maxn], all[maxn], color[maxn], outd[maxn], inde[maxn], tot, ind = 1;
bool instack[maxn];
stack<int> st;
vector<int> G[maxn];
void tarjan(int u){
dfn[u] = low[u] = ind++;
st.push(u);
instack[u] = true;
for (int v : G[u]){
if (dfn[v] == 0){
tarjan(v);
low[u] = min(low[u], low[v]);
}
else if (instack[v]){
low[u] = min(low[u], dfn[v]);
}
}
if (dfn[u] == low[u]){
tot++;
int now;
do{
now = st.top(); st.pop();
instack[now] = false;
color[now] = tot;
all[tot]++;
} while(now != u);
}
}
void solve(){
int n;
scanf("%d", &n);
for (int i = 1; i <= n; ++i){
int v;
while (scanf("%d", &v), v){
G[i].push_back(v);
}
}
for (int i = 1;i <= n; ++i){
if (dfn[i] == 0){
tarjan(i);
}
}
int ans1 = 0, ans2 = 0;
for (int u = 1; u <= n; ++u){
for (int v : G[u]){
//统计缩点后的出度情况
if (color[u] != color[v]){
inde[color[v]]++;
outd[color[u]]++;
}
}
}
//对缩点后进行遍历
for (int i = 1; i <= tot; ++i){
//入度为0的缩点,就需要投放一个软件
if (!inde[i]) ans1++;
if (!outd[i]) ans2++;
}
//当此图为强连通图时需要特判。
if (tot == 1) puts("1\n0");
else printf("%d\n%d\n", ans1, max(ans1, ans2));
}
int main(){
solve();
return 0;
}
/**
5
5 0
1 0
1 0
1 2 0
2 0
*/