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 }
View Code

 

posted @ 2020-04-09 11:56  kongbursi  阅读(149)  评论(0编辑  收藏  举报