您的位置:首页 > 运维架构

POJ 2186 Popular Cows (强连通分量)

2014-09-19 11:44 405 查看
题目类型 强连通分量

题目意思
给出 n (n<=10000) 个点和 m(<=50000) 条有向边 问有多少个点满足 其他点到这个点都可达

解题方法

求出强连通分量后 把在同一个强连通分量中的点看成一个点(即缩成一个点)  这时点与点之间还可能存在有向边(其实就是桥)

那么要达成题目的要求 则出度为 0 的点只能有一个 而这个点对应的强连通分量包含的点数即题目所求

参考代码 - 有疑问的地方在下方留言 看到会尽快回复的
#include <iostream>
#include <cstdio>
#include <cstring>
#include <stack>
#include <vector>

using namespace std;

const int maxn = 1e4 + 10;

vector<int>G[maxn];
int pre[maxn], lowlink[maxn], sccno[maxn], dfs_clock, scc_cnt;
int d[maxn];
stack<int>S;

void dfs(int u) {
pre[u] = lowlink[u] = ++dfs_clock;
S.push(u);
for( int i=0; i<G[u].size(); i++ ) {
int v = G[u][i];
if(!pre[v]) {
dfs(v);
lowlink[u] = min(lowlink[u], lowlink[v]);
}
else if(!sccno[v]) {
lowlink[u] = min(lowlink[u], pre[v]);
}
}
if(lowlink[u] == pre[u]) {
scc_cnt++;
for(;;) {
int x = S.top(); S.pop();
sccno[x] = scc_cnt;
if(x == u) break;
}
}
}

void find_scc(int n) {
dfs_clock = scc_cnt = 0;
memset(sccno, 0, sizeof(sccno));
memset(pre, 0, sizeof(pre));
for( int i=1; i<=n; i++ ) {
if(!pre[i]) dfs(i);
}
}

int main() {
freopen("in", "r", stdin);
int n, m;
while(scanf("%d%d", &n, &m) !=  EOF) {
for( int i=1; i<=n; i++ ) G[i].clear();
for( int i=0; i<m; i++ ) {
int u, v;
scanf("%d%d", &u, &v);
G[u].push_back(v);
}
find_scc(n);
memset(d, 0, sizeof(d));
for( int i=1; i<=n; i++ ) {
for( int j=0; j<G[i].size(); j++ ) {
int v = G[i][j];
if(sccno[i] != sccno[v]) {
d[sccno[i]]++;
}
}
}
int ans = 0, nans = 1;
for( int i=1; i<=scc_cnt; i++ ) {
if(d[i] == 0) {
ans++;
nans = i;
}
}
if(ans > 1) printf("0\n");
else {
ans = 0;
for( int i=1; i<=n; i++ ) if(sccno[i] == nans) ans++;
printf("%d\n", ans);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: