https://www.acwing.com/problem/content/1178/
我们的郭嘉大大在曹操这过得逍遥自在,但是有一天曹操给了他一个任务,在建邺城内有 N N N个袁绍的奸细,将他们从 1 1 1到 N N N进行编号,同时他们之间存在一种传递关系,即若 C i , j = 1 C_{i,j}=1 Ci,j=1,则奸细 i i i能将消息直接传递给奸细 j j j。现在曹操要发布一个假消息,需要传达给所有奸细,而我们的郭嘉大大则需要传递给尽量少的奸细使所有的奸细都知道这一个消息,问我们至少要传给几个奸细?
输入格式:
第一行为
N
N
N。
第二行至第
N
+
1
N+1
N+1行为
N
×
N
N×N
N×N的矩阵(若第
I
I
I行第
J
J
J列为
1
1
1,则奸细
I
I
I能将消息直接传递给奸细
J
J
J,若第
I
I
I行第
J
J
J列为
0
0
0,则奸细
I
I
I不能将消息直接传递给奸细
J
J
J)。
输出格式:
共一行,即我们的郭嘉大大首先至少要传递的奸细个数。
数据范围:
1
≤
N
≤
1000
1≤N≤1000
1≤N≤1000
可以先求强连通分量并缩点,然后求入度为 0 0 0的强连通分量有多少个,这些分量互相不可达,并且只需要他们知道了消息,就能使得所有人都知道消息。代码如下:
#include <iostream>
#include <cstring>
using namespace std;
const int N = 1010;
int n;
bool g[N][N];
int dfn[N], low[N], timestamp;
int stk[N], top;
int id[N], din[N], scc_cnt;
bool in_stk[N];
void tarjan(int u) {
dfn[u] = low[u] = ++timestamp;
stk[top++] = u, in_stk[u] = true;
for (int v = 1; v <= n; v++)
if (g[u][v]) {
if (!dfn[v]) {
tarjan(v);
low[u] = min(low[u], low[v]);
} else if (in_stk[v]) low[u] = min(low[u], dfn[v]);
}
if (dfn[u] == low[u]) {
int y;
scc_cnt++;
do {
y = stk[--top];
in_stk[y] = false;
id[y] = scc_cnt;
} while (y != u);
}
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
scanf("%d", &g[i][j]);
for (int i = 1; i <= n; i++)
if (!dfn[i])
tarjan(i);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
if (g[i][j] && id[i] != id[j])
din[id[j]]++;
int res = 0;
for (int i = 1; i <= scc_cnt; i++)
if (!din[i]) res++;
printf("%d\n", res);
}
时间复杂度 O ( N 2 ) O(N^2) O(N2),空间 O ( N ) O(N) O(N)。