POJ 2186
题目链接:
http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=16578
题意:
给一个有向图,问图上所有点都能到它的点有多少个。
思路:
1A好开森。
求强连通分量,练习kosaraju。最后缩个点然后topo一下结束。
Kosaraju原理:先按照原图dfs的topo一次,然后在根据反topo序dfs找强连通分量,和双连通分量类似。因为不会有类似割点的点同时属于两个强连通分量,所以只记录一次某点是属于哪个强连通分量即可。
源码:
#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <iostream>
#include <stack>
#include <queue>
using namespace std;
const int MAXN = 10000 + 5;
vector<int>lin[MAXN], G[MAXN], shrink[MAXN];
stack<int>sta;
int clock, vis[MAXN];
int sccno[MAXN], scc_cnt;
int n, m;
int num[MAXN];
int in[MAXN];
int sra[MAXN];
queue<int>que;
void dfs1(int u)
{
if(vis[u]) return;
vis[u] = 1;
for(int i = 0 ; i < (int)lin[u].size() ; i++){
int v = lin[u][i];
if(vis[v]) continue;
dfs1(v);
}
sta.push(u);
}
void dfs2(int u)
{
if(sccno[u]) return;
sccno[u] = scc_cnt;
for(int i = 0 ; i < (int)G[u].size() ; i++){
int v = G[u][i];
if(sccno[v]) continue;
dfs2(v);
}
}
void kosaraju()
{
scc_cnt = clock = 0;
memset(sccno, 0, sizeof(sccno));
memset(vis, 0, sizeof(vis));
while(!sta.empty()) sta.pop();
for(int i = 1 ; i <= n ; i++)
if(vis[i] == 0) dfs1(i);
while(!sta.empty()){
int to = sta.top();
sta.pop();
if(sccno[to]) continue;
scc_cnt++;
dfs2(to);
}
}
int main()
{
while(scanf("%d%d", &n, &m) != EOF){
for(int i = 1 ; i <= n ; i++)
lin[i].clear(), G[i].clear();
int u, v;
for(int i = 1 ; i <= m ; i++){
scanf("%d%d", &u, &v);
lin[u].push_back(v);
G[v].push_back(u);
}
kosaraju();
memset(sra, 0, sizeof(sra));
for(int i = 1 ; i <= n ; i++)
sra[sccno[i]]++;
for(int i = 1 ; i <= scc_cnt ; i++)
shrink[i].clear();
memset(in, 0, sizeof(in));
for(int i = 1 ; i <= n ; i++){
for(int j = 0 ; j < (int)lin[i].size() ; j++){
int u = i, v = lin[i][j];
if(sccno[u] != sccno[v]){
shrink[sccno[u]].push_back(sccno[v]);
in[sccno[v]]++;
}
}
}
while(!que.empty()) que.pop();
for(int i = 1 ; i <= scc_cnt ; i++)
num[i] = 1;
for(int i = 1 ; i <= scc_cnt ; i++){
if(in[i] == 0)
que.push(i);
}
while(!que.empty()){
int org = que.front(); que.pop();
for(int i = 0 ; i < (int)shrink[org].size() ; i++){
int v = shrink[org][i];
in[v]--;
num[v] += num[org];
if(in[v] == 0)
que.push(v);
}
}
// for(int i = 1 ; i <= scc_cnt ; i++){
// printf("i = %d, sra[%d] = %d\n", i, i, sra[i]);
// }
// for(int i = 1 ; i <= n ; i++){
// printf("sccno[%d] = %d\n", i, sccno[i]);
// }
// printf("shrink\n");
// for(int i = 1 ; i <= scc_cnt ; i++){
// printf("sccno = %d shrink = ", i);
// for(int j = 0 ; j < (int)shrink[i].size() ; j++)
// printf("%d ", shrink[i][j]);
// printf("\n");
// }
// printf("shrink\n");
int ans = 0;
for(int i = 1 ; i <= scc_cnt ; i++)
if(num[i] == scc_cnt) ans += sra[i];/// printf("i = %d\n", i);
printf("%d\n", ans);
}
return 0;
}