小海酷爱数学,他的梦想是在太平洋上建立一个数学王国。
终于有一天,他的同学小升研发出了一类叫做“数学分子”的东西,并兴高采烈地跑来找到他,给了他 $N$ 种“数学分子”,按 $1$ 到 $N$ 依次编号。小海要用部分“数学分子”投放到太平洋上构建数学王国。
已知每种“数学分子”都可以掌控另一种“数学分子”。小海希望他能够掌控整个数学王国,因此,他希望 **所有被投放的“数学分子”都有至少一个没有被投放的“数学分子”能掌控它**。
小海想知道,**最多**可以投放的“数学分子”的种类数目。
1.第一个特征,发现每一个点只可能有一个出边。 图形一定有大于等于一个的简单环。
2.通过找规律发现,链上的点黑白染色即可。环上和链上的连接处,如果是被管的点,则相当于把环断开了。如果是管别人的点,也可能作为被管的点。因此,最终成为一个完整的环。
//一个特性: //被管理的点,一定不用进栈。进栈的点,是管别人的.管别人的和被管的都要打标记。 //其余没有打过标记的一定是不相交的环。 #include <bits/stdc++.h> using namespace std; stack<int> q; int to[1000005], ru[1000005], n, cnt, b[1000005], tot; int main() { cin >> n; for (int i = 1; i <= n; i++) { cin >> to[i]; ru[to[i]]++; } for (int i = 1; i <= n; i++) { if (ru[i] == 0) q.push(i), b[i] = 1; } //将边砍掉 while (!q.empty()) { int u = q.top(); q.pop(); int v = to[u]; if (b[v] == 0) { cnt++; b[v] = 1; //被管的打标记 ru[to[v]]--; if (ru[to[v]] == 0) q.push(to[v]), b[to[v]] = 1; //管别人的打标记 } } //接下来只可能是不相交的环 for (int i = 1; i <= n; i++) { if (b[i] == 0) { int v = to[i], tot = 1; //还有一种自环 b[i] = 1; while (v != i) { b[v] = 1; tot++; v = to[v]; } cnt += tot / 2; } } cout << cnt << endl; return 0; } /* 12 4 4 4 5 6 8 5 9 10 11 8 11 12 4 4 4 5 8 12 5 9 10 11 8 11 */