给你一个有向图,然后问你有多少个满足要求的点,要求是: 这个点能走到的所有点都能走回这个点,找到所有的这样的点,然后排序输出。
思路:
可以直接一遍强连通缩点,所点之后出度为0的强连通点中所包含的点都是满足要求的,比较容易理解,在强连通里,所有点都能走回来,同时只要强连通所点后没有出度,那么就能保证里面的每个点到所有连接自己连接的点后都能走回来,还有就是这个题目我数组开到快 80000000了,还没MLE,这个我就不说什么了。
#include<stdio.h>
#include<string.h>
#include<stack>
#include<algorithm>
#define N_node 5001
#define N_edge 5000 * 5000 + 1
using namespace std;
typedef struct
{
int to ,next;
}STAR;
typedef struct
{
int a ,b;
}EDGE;
EDGE edge[N_edge];
STAR E1[N_edge] ,E2[N_edge];
int list1[N_node] ,list2[N_node] ,tot;
int Belong[N_node] ,Cnt;
int mark[N_node] ,Ans[N_node];
stack<int>sk;
void add(int a ,int b)
{
E1[++tot].to = b;
E1[tot].next = list1[a];
list1[a] = tot;
E2[tot].to = a;
E2[tot].next = list2[b];
list2[b] = tot;
}
void DFS1(int x)
{
mark[x] = 1;
for(int k = list1[x] ;k ;k = E1[k].next)
{
int to = E1[k].to;
if(mark[to]) continue;
DFS1(to);
}
sk.push(x);
}
void DFS2(int x)
{
mark[x] = 1;
Belong[x] = Cnt;
for(int k = list2[x] ;k ;k = E2[k].next)
{
int to = E2[k].to;
if(mark[to]) continue;
DFS2(to);
}
}
int main ()
{
int n ,m ,i ,a ,b;
while(~scanf("%d" ,&n) && n)
{
scanf("%d" ,&m);
memset(list1 ,0 ,sizeof(list1));
memset(list2 ,0 ,sizeof(list2));
tot = 1;
for(i = 1 ;i <= m ;i ++)
{
scanf("%d %d" ,&a ,&b);
edge[i].a = a ,edge[i].b = b;
add(a ,b);
}
memset(mark ,0 ,sizeof(mark));
while(!sk.empty()) sk.pop();
for(i = 1 ;i <= n ;i ++)
if(!mark[i]) DFS1(i);
memset(mark ,0 ,sizeof(mark));
Cnt = 0;
while(!sk.empty())
{
int xin = sk.top();
sk.pop();
if(mark[xin]) continue;
Cnt ++;
DFS2(xin);
}
memset(mark ,0 ,sizeof(mark));
for(i = 1 ;i <= m ;i ++)
{
a = Belong[edge[i].a];
b = Belong[edge[i].b];
if(a == b) continue;
mark[a] ++;
}
int nowid = 0;
for(i = 1 ;i <= n ;i ++)
if(!mark[Belong[i]]) Ans[++nowid] = i;
sort(Ans + 1 ,Ans + nowid + 1);
for(i = 1 ;i <= nowid ;i ++)
if(i == nowid) printf("%d
" ,Ans[i]);
else printf("%d " ,Ans[i]);
}
return 0;
}