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 }

原文地址:https://www.cnblogs.com/kongbursi-2292702937/p/12665925.html

时间: 2024-08-29 19:12:47

POJ - 2553 tarjan算法+缩点的相关文章

tarjan算法+缩点--cojs 908. 校园网

cojs 908. 校园网 ★★   输入文件:schlnet.in   输出文件:schlnet.out   简单对比时间限制:1 s   内存限制:128 MB USACO/schlnet(译 by Felicia Crazy) 描述 一些学校连入一个电脑网络.那些学校已订立了协议:每个学校都会给其它的一些学校分发软件(称作“接受学校”).注意如果 B 在 A 学校的分发列表中,那么 A 不必也在 B 学校的列表中. 你要写一个程序计算,根据协议,为了让网络中所有的学校都用上新软件,必须接受

tarjan算法+缩点:求强连通分量 POJ 2186

强连通分量:1309. [HAOI2006]受欢迎的牛 ★★   输入文件:cow.in   输出文件:cow.out   简单对比时间限制:1 s   内存限制:128 MB [题目描述] 每一头牛的愿望就是变成一头最受欢迎的牛.现在有N头牛,给你M对整数(A,B),表示牛 A 认为牛 B受欢迎.这种关系是具有传递性的,如果A认为B受欢迎,B认为C受欢迎,那么牛A也认为牛C受欢迎.你的任务是求出有多少头牛被所有的牛认为是受欢迎的. [输入格式] 第1行两个整数N,M: 接下来M行,每行两个数A

poj2186tarjan算法缩点求出度

poj2186tarjan算法缩点求出度 自己打一遍第一题,入门啦,入门啦 题目还算简单,多头牛,给你仰慕关系(可传递),问你最后有没有牛被所有的牛仰慕 根据关系可以建图,利用tarjan算法缩点处理后,得到有向无环图,缩成的点都是相互仰慕的,所以根据传递性也就是可以看成一个点了,然后染色分块,计算每一块的出度. 如果出度为0有且仅有一个,那么输出该块内所有的点,都符合要求 如果有多个直接输出0即可 #include <iostream> #include <cstdio> #in

POJ 2553 The Bottom of a Graph TarJan算法题解

本题分两步: 1 使用Tarjan算法求所有最大子强连通图,并且标志出来 2 然后遍历这些节点看是否有出射的边,没有的顶点所在的子强连通图的所有点,都是解集. Tarjan算法就是模板算法了. 这里使用一个数组和一个标识号,就可以记录这个顶点是属于哪个子强连通图的了. 然后使用DFS递归搜索所有点及其边,如果有边的另一个顶点不属于本子强连通图,那么就说明有出射的边. 有难度的题目: #include <stdio.h> #include <stdlib.h> #include &l

POJ 2553 The Bottom of a Graph(Tarjan,强连通分量)

解题思路: 本题要求 求出所有满足"自己可达的顶点都能到达自己"的顶点个数,并从小到大输出. 利用Tarjan算法求出强连通分量,统计每个强连通分量的出度,出度为0的强连通分量内的顶点即为所求顶点. #include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> #include <algorithm> #include <cmath

poj 2553强连通+缩点

/*先吐槽下,刚开始没看懂题,以为只能是一个连通图0T0 题意:给你一个有向图,求G图中从v可达的所有点w,也都可以达到v,这样的v称为sink.求这样的v. 解;求强连通+缩点.求所有出度为0的点即为要求的点. 注意:可能有多个联通分支. */ #include<stdio.h> #include<string.h> #include<stdlib.h> #define N 5100 struct node { int u,v,w,next; }bian[N*N*2]

POJ - 1470 Closest Common Ancestors(离线Tarjan算法)

1.输出测试用例中是最近公共祖先的节点,以及这个节点作为最近公共祖先的次数. 2.最近公共祖先,离线Tarjan算法 3. /* POJ 1470 给出一颗有向树,Q个查询 输出查询结果中每个点出现次数 */ /* 离线算法,LCATarjan 复杂度O(n+Q); */ #include<iostream> #include<stdio.h> #include<string.h> using namespace std; const int MAXN=1010; co

Tarjan算法各种&amp;RMQ&amp; POJ 3694

关于tarjan 的思想可以在网上搜到,具体我也不太清楚,应该说自己理解也不深,下面是做题经验得到的一些模板. 其中有很多转载,包括BYVoid等,感谢让我转...望各路大神愿谅 有向图求连通分量的一般方法: 1 void Tarjan(u) { 2 dfn[u]=low[u]=++index 3 stack.push(u) 4 for each (u, v) in E { 5 if (v is not visted) { 6 tarjan(v) 7 low[u] = min(low[u], l

【POJ 1330 Nearest Common Ancestors】LCA Tarjan算法

题目链接:http://poj.org/problem?id=1330 题意:给定一个n个节点的有根树,以及树中的两个节点u,v,求u,v的最近公共祖先. 数据范围:n [2, 10000] 思路:从树根出发进行后序深度优先遍历,设置vis数组实时记录是否已被访问. 每遍历完一棵子树r,把它并入以r的父节点p为代表元的集合.这时判断p是不是所要求的u, v节点之一,如果r==u,且v已访问过,则lca(u, v)必为v所属集合的代表元.p==v的情况类似. 我的第一道LCA问题的Tarjan算法