| Time Limit: 3000MS | Memory Limit: 65536K | |
| Total Submissions: 9575 | Accepted: 3984 |
Description
Input
Output

Sample Input
3 3 1 3 2 3 3 1 2 1 1 2 0
Sample Output
1 3 2
解析偷偷粘的阿宇的博客,
定义:点v是汇点须满足 --- 对图中任意点u,若v可以到达u则必有u到v的路径;若v不可以到达u,则u到v的路径可有可无。
题意:在n个点m条边的有向图里面,问有多少个点是汇点。
分析:首先若SCC里面有一个点不是汇点,那么它们全不是汇点,反之也如此。这也就意味着一个SCC里面的点要么全是,要么全不是。在求出SCC并缩点后,任一个编号为A的SCC若存在指向编号为B的SCC的边,那么它里面所有点必不是汇点(因为编号为B的SCC不可能存在指向编号为A的SCC的边)。若编号为A的SCC没有到达其他SCC的路径,那么该SCC里面所有点必是汇点。因此判断的关键在于SCC的出度是否为0.
思路:先用tarjan求出所有SCC,然后缩点后找出所有出度为0的SCC,并用数字存储点,升序排列后输出。
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#define maxn 5000
#define maxm 5000 * 5000
using namespace std;
int n, m;
struct node{
int u, v, next;
};
node edge[maxm];
int head[maxn], cnt;
int low[maxn], dfn[maxn];
int dfs_clock;
int Stack[maxn], top;
bool Instack[maxn];
int Belong[maxn];
int scc_clock;
int in[maxn], out[maxn];
vector<int>scc[maxn];
int num[maxn];
void init(){
cnt = 0;
memset(head, -1, sizeof(head));
}
void addedge(int u, int v){
edge[cnt] = {u, v, head[u]};
head[u] = cnt++;
}
void getmap(){
while(m--){
int a, b;
scanf("%d%d", &a, &b);
addedge(a, b);
}
}
void Tarjan(int u, int per){
int v;
low[u] = dfn[u] = ++dfs_clock;
Stack[top++] = u;
Instack[u] = true;
for(int i = head[u]; i != -1; i = edge[i].next){
int v = edge[i].v;
if(!dfn[v]){
Tarjan(v, u);
low[u] = min(low[u], low[v]);
}
else if(Instack[v])
low[u] = min(low[u], dfn[v]);
}
if(dfn[u] == low[u]){
scc_clock++;
scc[scc_clock].clear();
do{
v = Stack[--top];
Instack[v] = false;
Belong[v] = scc_clock;
scc[scc_clock].push_back(v);
}
while( v != u);
}
}
void suodian(){
for(int i = 1; i <= scc_clock; ++i){
out[i] = 0;
}
for(int i = 0; i < cnt; ++i){
int u = Belong[edge[i].u];
int v = Belong[edge[i].v];
if(u != v)
out[u]++;
}
}
void find(){
memset(low, 0, sizeof(low));
memset(dfn, 0, sizeof(dfn));
memset(Belong, 0, sizeof(Belong));
memset(Stack, 0, sizeof(Stack));
memset(Instack, false, sizeof(false));
dfs_clock = scc_clock = top = 0;
for(int i = 1; i <= n ; ++i){
if(!dfn[i])
Tarjan(i, i);
}
}
void solve(){
int k = 0;
for(int i = 1; i <= scc_clock; ++i){
if(out[i] == 0){
for(int j = 0; j < scc[i].size(); ++j)
num[k++] = scc[i][j];
}
}
sort(num, num + k);
for(int i = 0; i < k; ++i){
if(!i)
printf("%d", num[i]);
else
printf(" %d", num[i]);
}
printf("\n");
}
int main (){
while(scanf("%d", &n), n){
scanf("%d", &m);
init();
getmap();
find();
suodian();
solve();
}
return 0;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
POJ 2553--The Bottom of a Graph【scc缩点构图 && 求出度为0的scc && 输出scc中的点】
原文地址:http://blog.csdn.net/hpuhjh/article/details/47802921