P11073 Game King
P11073 Game King - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
缩点,分别重建图,再建反图,可知,拓扑序大的一定不能到拓扑序小的。不断新建点统计。
#include <iostream>
#include <algorithm>
#include <cstring>
#include <unordered_map>
#include <queue>
using namespace std;
typedef pair<int, int> PII;
const int N = 1000010, M = N * 12;
int h[N], ne[M], e[M], idx, hr[N], hx[N];
int n, m, ans;
int dfn[N], low[N], timestamp;
int stk[N], top;
bool in_stk[N];
int id[N], scc_cnt, sizes[N];
int din[N], dout[N], din1[N], dout1[N];
double s1[N], s2[N];
int st[N];
void add(int *h, int a, int b)
{
e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}
void tarjan(int u)
{
dfn[u] = low[u] = ++ timestamp;
stk[ ++ top] = u; in_stk[u] = true;
for (int i = h[u]; i != -1; 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])
{
scc_cnt ++ ;
int y;
do {
y = stk[top -- ];
id[y] = scc_cnt;
sizes[scc_cnt] ++ ;
in_stk[y] = false;
}while (y != u);
}
}
int main()
{
cin >> n >> m;
memset(h, -1, sizeof h);
memset(hr, -1, sizeof hr);
memset(hx, -1, sizeof hx);
while (m -- )
{
int a, b;
scanf("%d%d", &a, &b);
if (a == b) continue;
add(h, a, b);
}
int cnt = 0;
for (int i = 1; i <= n; i ++ )
if (dfn[i] == 0)
{
tarjan(i);
cnt ++ ;
}
for (int u = 1; u <= n; u ++ )
{
for (int i = h[u]; i != -1; i = ne[i])
{
int j = e[i], a = id[u], b = id[j];
if (b != a)
{
add(hr, a, b);
add(hx, b, a);
}
}
}
int zero = 0, ans = 0; // 入度为零点数量,ans统计
for (int u = 1; u <= scc_cnt; u ++ )
{
zero ++ ;
for (int i = hr[u]; i != -1; i = ne[i])
{
int j = e[i];
if (din[j] == 0) zero -- ;
din[j] ++ ;
}
if (zero == 1) st[u] = 1;
}
zero = 0;
for (int u = scc_cnt; u; u -- )
{
zero ++ ;
for (int i = hx[u]; i != -1; i = ne[i])
{
int j = e[i];
if (dout[j] == 0) zero -- ;
dout[j] ++ ;
}
if (zero == 1 && st[u]) ans += sizes[u];
}
cout << ans << endl;
return 0;
}