链接
思路和代码
设缩点后,起点有 P P P 个,终点有 Q Q Q 个。
第一问,只要统计入度为 0 0 0 的点的数量,即 P P P 。
第二问:
- 若 S C C _ C N T = 1 SCC\_CNT=1 SCC_CNT=1 ,那么答案为 0 0 0
- 否则,答案为 m a x ( P , Q ) max(P, Q) max(P,Q)
简单思路:
-
设 P ≤ Q P\le Q P≤Q
-
当 P = 1 P=1 P=1 时,只需要让所有终点连向起点,答案为 Q Q Q
-
当 P > 1 P > 1 P>1 时,任选出两组起点和终点 p 1 , q 1 , p 2 , q 2 p_1,q_1,p_2,q_2 p1,q1,p2,q2 , 只需让 q 1 q_1 q1 连向 p 2 p_2 p2 ,那么 P = P − 1 , Q = Q − 1 P=P-1,Q=Q-1 P=P−1,Q=Q−1 ,依次这样操作直至 P = 1 P=1 P=1 ,化为第一种情况。
-
第二种情况答案为 Q − ( P − 1 ) + ( P − 1 ) = Q Q-(P-1)+(P-1) = Q Q−(P−1)+(P−1)=Q
-
还须特判一下,当只有一个强连通分量时,答案为 0 0 0
-
综上,第二问答案为
scc_cnt > 1 ? max(P, Q) : 0
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <iostream>
#include <sstream>
#include <algorithm>
#include <cmath>
#include <vector>
#include <stack>
#include <queue>
#include <deque>
#include <bitset>
#include <set>
#include <map>
#include <unordered_set>
#include <unordered_map>
#define endl '\n'
#define PI acos(-1)
#define LL long long
#define INF 0x3f3f3f3f
#define lowbit(x) (-x&x)
#define PII pair<int, int>
#define PIL pair<int, long long>
#define mem(a, b) memset(a, b, sizeof a)
#define rev(x) reverse(x.begin(), x.end())
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
const int N = 110, M = 10010;
int n;
int h[N], e[M], ne[M], idx;
int dfn[N], low[N], timestamp;
int din[N], dout[N];
int id[N], scc_cnt;
bool in_stk[N];
int stk[N], top;
void add(int a, int b) { // 加边函数
e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}
void tarjan(int u) { //tarjan算法求SCC
dfn[u] = low[u] = ++ timestamp;
stk[ ++ top] = u, in_stk[u] = true;
for (int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
if (!dfn[j]) {
tarjan(j);
low[u] = min(low[u], low[j]);
} else if (in_stk[j]) low[u] = min(low[u], dfn[j]);
}
if (low[u] == dfn[u]) {
int y;
++ scc_cnt;
do {
y = stk[top -- ];
in_stk[y] = false;
id[y] = scc_cnt;
} while (y != u);
}
}
void solve() {
// 设缩完点后有P个起点,Q个终点
// 第一问答案为P
// 如果强连通分量数量大于1,第二问答案为max(P, Q)
// 否则为0
// 初始化
mem(h, -1);
// 建图,加边
cin >> n;
for (int i = 1; i <= n; i ++ ) {
int t;
while (cin >> t, t) add(i, t);
}
// 求SCC
for (int i = 1; i <= n; i ++ ) if (!dfn[i]) tarjan(i);
// 求每个强连通分量的出入度
for (int i = 1; i <= n; i ++ ) {
for (int j = h[i]; ~j; j = ne[j]) {
int k = e[j];
int a = id[i], b = id[k];
if (a != b) { //a 和 b 不在同一强连通分量中
dout[a] ++ ;
din[b] ++ ;
}
}
}
// 求P和Q
int P = 0, Q = 0;
for (int i = 1; i <= scc_cnt; i ++ ) {
if (!din[i]) P ++ ;
if (!dout[i]) Q ++ ;
}
//输出结论
cout << P << endl;
cout << (scc_cnt > 1 ? max(P, Q) : 0) << endl;
}
int main() {
IOS;
solve();
return 0;
}