POJ - 2553 tarjan算法+缩点
题意:
给你n个点,和m条单向边,问你有多少点满足(G)={v∈V|∀w∈V:(v→w)⇒(w→v)}关系,并把这些点输出(要注意的是这个关系中是蕴含关系而不是且(&&)关系)
题解:
单独一个强连通分量中的所有点是满足题目要求的
但如果它连出去到了其他点那里,要么成为新的强连通分量,要么失去原有的符合题目要求的性质
所以只需tarjan缩点求出所有强连通分量,再O(E)枚举所有边,是否会成为连接一个分量与另一个分量的边——即一条出度——即可
如果一个分量没有出度,那么他中间的所有点都是符合题目要求的点
代码(多组输入记得每次初始化):
1 #include<stdio.h> 2 #include<string.h> 3 #include<iostream> 4 #include<algorithm> 5 #include<queue> 6 #include<map> 7 #include<vector> 8 #include<math.h> 9 #define mem(a,x) memset(a,x,sizeof(a)) 10 using namespace std; 11 const int maxn=50005; 12 const int mod=26; 13 const int INF=0x3f3f3f3f; 14 struct edge 15 { 16 int u,v,next; 17 bool sign; 18 } e[maxn*2]; 19 int head[maxn],cnt; 20 void add_edge(int x,int y) 21 { 22 e[cnt].u=x; 23 e[cnt].v=y; 24 e[cnt].next=head[x]; 25 head[x]=cnt++; 26 } 27 int dfn[maxn],low[maxn],stacks[maxn],top,tot; 28 int taj; 29 int belong[maxn],visit[maxn],result[maxn]; 30 vector<int>w[maxn]; 31 void tarjan(int x,int fx) 32 { 33 dfn[x]=low[x]=++tot; 34 stacks[top++]=x; 35 visit[x]=1; 36 for(int i=head[x]; i!=-1; i=e[i].next) 37 { 38 int v=e[i].v; 39 if(!dfn[v]) 40 { 41 tarjan(v,x); 42 low[x]=min(low[x],low[v]); 43 if(dfn[x]<low[v]) 44 { 45 e[i].sign=1; 46 } 47 } 48 else if(visit[v]) 49 { 50 low[x]=min(low[x],dfn[v]); 51 } 52 } 53 if(low[x]==dfn[x]) 54 { 55 int now; 56 taj++; 57 w[taj].clear(); 58 do 59 { 60 now=stacks[--top]; 61 visit[now]=0; 62 belong[now]=taj; 63 w[taj].push_back(now); 64 } 65 while(now!=x); 66 } 67 } 68 void tarjan_init(int n) 69 { 70 memset(visit,0,sizeof(visit)); 71 memset(low,0,sizeof (low)); 72 memset(dfn,0,sizeof (dfn)); 73 memset(stacks,0,sizeof (stacks)); 74 memset(belong,0,sizeof belong); 75 top=tot=taj=0; 76 for(int i=1; i<=n; ++i) 77 { 78 if(!dfn[i]) tarjan(i,i); 79 } 80 } 81 vector<int>g[maxn]; 82 int cu[maxn],ru[maxn]; 83 void suodian() 84 { 85 memset(cu,0,sizeof(cu)); 86 memset(ru,0,sizeof(ru)); 87 for(int i=1; i<=taj; ++i) 88 g[i].clear(); 89 for(int i=0; i<cnt; ++i) 90 { 91 int u=belong[e[i].u]; 92 int v=belong[e[i].v]; 93 if(u!=v) g[u].push_back(v),cu[u]++,ru[v]++;//printf("%d %d\n",u,v); 94 } 95 } 96 int vis[maxn]; 97 void init() 98 { 99 memset(head,-1,sizeof(head)); 100 cnt=0; 101 } 102 int main() 103 { 104 int n,m; 105 while(~scanf("%d",&n)) 106 { 107 if(n==0) return 0; 108 scanf("%d",&m); 109 init(); 110 for(int i=1; i<=m; ++i) 111 { 112 int a,b; 113 scanf("%d%d",&a,&b); 114 add_edge(a,b); 115 } 116 tarjan_init(n); 117 suodian(); 118 int index=0; 119 for(int i=1;i<=n;++i) 120 { 121 if(cu[belong[i]]==0) 122 result[index++]=i; 123 } 124 if(index==0) 125 { 126 printf("\n"); 127 continue; 128 } 129 sort(result,result+index); 130 for(int i=0;i<index;++i) 131 if(i==index-1) 132 printf("%d\n",result[i]); 133 else printf("%d ",result[i]); 134 } 135 return 0; 136 }