POJ 2553 The Bottom of a Graph (强连通分量+缩点)
题意:给定n个点和他们的有向关系,求出这个有向图中所有的sink点,sink点定义:如果一个点u为sink点,那么他所有能到达的点v,也能有一条通路v->u存在。
思路:根据sink点的定义,我们很容易想到了强连通分量,但是思考如下情形:如果强连通分支A中有一点u,可以到到强连通分支B中的一点v,由强连通分支定义,v肯定无法到达u,那么A中所有的就不是sink点。所以在求完强联通分支后,还要检验强连通分支之间的关系,只有与其他强联通分支无关的分支中的点才是sink点。此题中求强连通分量用的是前后两边DFS。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <memory.h>
#include <cmath>
#include <ctime>
#include <bitset>
#include <queue>
#include <vector>
using namespace std;
const int BORDER = (1<<20)-1;
const int MAXSIZE = 37;
const int MAXN = 5050;
const int INF = 1000000000;
#define CLR(x,y) memset(x,y,sizeof(x))
#define ADD(x) x=((x+1)&BORDER)
#define IN(x) scanf("%d",&x)
#define OUT(x) printf("%d\n",x)
#define MIN(m,v) (m)<(v)?(m):(v)
#define MAX(m,v) (m)>(v)?(m):(v)
#define ABS(x) ((x)>0?(x):-(x))
typedef struct{
int v,next;
}Edge;
Edge edge_r[MAXN*MAXN],edge_p[MAXN*MAXN];
vector<int> vet[MAXN];
int n,m,index_r,index_p,cnt;
bool visit[MAXN];
int order[MAXN],net_p[MAXN],net_r[MAXN],set[MAXN];
bool b_set[MAXN];
void add_edge(Edge* edge,int* net,int& index,const int& u,const int& v)
{
edge[index].v = v;
edge[index].next = net[u];
net[u] = index++;
}
int init()
{
CLR(visit,0);
CLR(order,0);
CLR(net_r,-1);
CLR(net_p,-1);
CLR(set,0);
CLR(b_set,0);
for(int i = 0; i < MAXN; ++i)
vet[i].clear();
index_r = index_p = 0;
return 0;
}
int input()
{
int u,v;
for(int i = 0; i < m; ++i)
{
scanf("%d%d",&u,&v);
add_edge(edge_p,net_p,index_p,u,v);
add_edge(edge_r,net_r,index_r,v,u);
}
return 0;
}
void dfs_p(const int& u)
{
visit[u] = true;
for(int i = net_p[u]; i != -1; i = edge_p[i].next)
if(!visit[edge_p[i].v])
dfs_p(edge_p[i].v);
order[++cnt] = u;
}
void dfs_r(const int& u)
{
visit[u] = true;
set[u] = cnt;
vet[cnt].push_back(u);
for(int i = net_r[u]; i != -1; i = edge_r[i].next)
if(!visit[edge_r[i].v])
dfs_r(edge_r[i].v);
}
void _check()
{
int i,j,tmp;
for(i = 1; i <= n; ++i)
{
if(b_set[set[i]] )
continue;
for(j = net_p[i]; j != -1; j = edge_p[j].next)
if(set[i] != set[edge_p[j].v])
break;
if(j != -1)
b_set[set[i]] = true;
}
}
int work()
{
int i,j,tmp,v,u,ans;
cnt = 0;
for(i = 1; i <= n; ++i)
if(!visit[i])
dfs_p(i);
CLR(visit,0);
cnt = 0;
for(i = n; i > 0; --i)
if(!visit[order[i]])
{
++cnt;
dfs_r(order[i]);
}
_check();
CLR(visit,0);
for(i = 1; i <= cnt; ++i)
{
if(b_set[i])
continue;
for(j = 0; j < vet[i].size(); ++j)
visit[vet[i][j]] = true;
}
int index = 0;
for(i = 1; i <= n; ++i)
if(visit[i])
set[index++] = i;
if(index == 0)
printf("\n");
else
{
printf("%d",set[0]);
for(i = 1; i < index; ++i)
printf(" %d",set[i]);
printf("\n");
}
return 0;
}
int main()
{
while(IN(n) && n)
{
IN(m);
init();
input();
work();
}
return 0;
}