codevs 2822 爱在心中 tarjan(强联通分量)

2822 爱在心中

时间限制: 1 s

空间限制: 128000 KB

题目等级 : 钻石 Diamond

题目描述 Description

“每个人都拥有一个梦,即使彼此不相同,能够与你分享,无论失败成功都会感动。爱因为在心中,平凡而不平庸,世界就像迷宫,却又让我们此刻相逢Our Home。”

在爱的国度里有N个人,在他们的心中都有着一个爱的名单,上面记载着他所爱的人(不会出现自爱的情况)。爱是具有传递性的,即如果A爱B,B爱C,则A也爱C。
如果有这样一部分人,他们彼此都相爱,则他们就超越了一切的限制,用集体的爱化身成为一个爱心天使。
现在,我们想知道在这个爱的国度里会出现多少爱心天使。而且,如果某个爱心天使被其他所有人或爱心天使所爱则请输出这个爱心天使是由哪些人构成的,否则输出-1。

输入描述 Input Description

第1行,两个数N、M,代表爱的国度里有N个人,爱的关系有M条。
第2到第M+1行,每行两个数A、B,代表A爱B。

输出描述 Output Description

第1行,一个数,代表爱的国度里有多少爱心天使。
第2行,如果某个爱心天使被其他所有人和爱心天使所爱则请输出这个爱心天使是由哪些人构成的(从小到大排序),否则输出-1。

样例输入 Sample Input

样例输入1:

6 7
1 2
2 3
3 2
4 2
4 5
5 6
6 4

样例输入2:

3 3
1 2
2 1
2 3

样例输出 Sample Output

样例输出1:

2
2 3

样例输出2:

1
-1

数据范围及提示 Data Size & Hint

各个测试点1s

-------------------------------------------------------------------------------------------------------------------

这道题的第一问,先用tarjan找出图中所有的强联通分量,找出两个点及以上的强联通分量即题中的爱心天使

那第二问呢?

我们需要一步缩点操作

就是把每个强联通分量缩成一个点,建成另一个新的图,而且这个图肯定不带环(树或森林)

然后找出“爱心天使”中出度为0的点,从这个点开始遍历新图的反图,倘若所有点都能够遍历到,则说明“这个爱心天使被其他所有人或爱心天使所爱”,否则就不行

那为什么要找出度为0的点呢?

因为按题目的定义,这个爱心天使要能被所有点到达,又新图中不带环,所以不能有出度;从这里也可以看出满足条件的点最多只有一个

AC代码:

 1 #include<stdio.h>
 2 #include<string.h>
 3 #define maxn 10010
 4 struct node{
 5     int to,next,fr;
 6 };
 7 node e[maxn],tr[maxn];
 8 int n,m,belong[maxn],dfn[maxn],low[maxn],stack[maxn],cnt,pre[maxn],time,top,bcnt,pretr[maxn],wrt,size[maxn],dcnt,po[maxn],pref[maxn];
 9 bool instack[maxn],pd[maxn];
10 void buildtr(int,int);
11 void tarjan(int);
12 void build(int,int);
13 void dfs(int);
14 int read();
15 int main(){
16     n=read();m=read();time=0;top=0;bcnt=0;wrt=0;dcnt=0;
17     for(int i=1;i<=m;i++){
18         int a=read(),b=read();
19         build(a,b);
20     }
21     for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
22     for(int i=1;i<=bcnt;i++) if(size[i]>1) po[++dcnt]=i;//第一问
23     printf("%d\n",dcnt);
24     cnt=0;
25     for(int i=1;i<=m;i++)
26        if(belong[e[i].to]!=belong[e[i].fr])
27        buildtr(belong[e[i].fr],belong[e[i].to]);
28     for(int i=1;i<=dcnt;i++)
29        if(!pretr[po[i]]){
30            memset(pd,0,sizeof(pd));
31            dfs(po[i]);
32            bool flag=true;
33            for(int j=1;j<=bcnt;j++)
34               if(!pd[j]){
35                   flag=false;
36                   break;
37               }
38            if(flag) wrt=po[i];
39            break;//因为满足条件的点只有一个,而且如果这个点不满足,往后也不满足,所以找到一个点出度为0的时候就可以退出了 ,
40        }
41     if(!wrt) printf("-1");
42     else
43        for(int i=1;i<=n;i++)
44            if(belong[i]==wrt)
45            printf("%d ",i);
46     return 0;
47 }
48 void dfs(int x){
49     pd[x]=1;
50     for(int i=pref[x];i;i=tr[i].next) dfs(tr[i].to);
51 }
52 void buildtr(int x,int y){
53     tr[++cnt].to=y;tr[cnt].next=pretr[x];pretr[x]=cnt;//新图
54     tr[++cnt].to=x;tr[cnt].next=pref[y];pref[y]=cnt;//新图的反图
55 }
56 void tarjan(int x){
57     dfn[x]=low[x]=++time;
58     instack[x]=1;stack[++top]=x;
59     for(int i=pre[x];i;i=e[i].next){
60         int to=e[i].to;
61         if(!dfn[to]){
62             tarjan(to);
63             if(low[to]<low[x]) low[x]=low[to];
64         }
65         else if(instack[to]&&dfn[to]<low[x]) low[x]=dfn[to];
66     }
67     if(dfn[x]==low[x]){
68         bcnt++;
69         int k;
70         do{
71             k=stack[top--];
72             instack[k]=0;
73             belong[k]=bcnt;
74             size[bcnt]++;
75         }while(k!=x);
76     }
77 }
78 void build(int x,int y){
79     e[++cnt].to=y;e[cnt].next=pre[x];pre[x]=cnt;e[cnt].fr=x;
80 }
81 int read(){
82     int ans=0,f=1;char c=getchar();
83     while(‘0‘>c||c>‘9‘){if(c==‘-‘)f=-1;c=getchar();}
84     while(‘0‘<=c&&c<=‘9‘)ans=ans*10+c-48,c=getchar();return ans*f;
85 }

tarjan

时间: 2024-08-06 11:54:08

codevs 2822 爱在心中 tarjan(强联通分量)的相关文章

codevs 2822 爱在心中

codevs 2822 爱在心中 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description “每个人都拥有一个梦,即使彼此不相同,能够与你分享,无论失败成功都会感动.爱因为在心中,平凡而不平庸,世界就像迷宫,却又让我们此刻相逢Our Home.” 在爱的国度里有N个人,在他们的心中都有着一个爱的名单,上面记载着他所爱的人(不会出现自爱的情况).爱是具有传递性的,即如果A爱B,B爱C,则A也爱C.如果有这样一部分人,他们彼此都相爱,则

tarjan 强联通分量和割点

1 #include<cstdio> 2 #include<cstring> 3 #include<cmath> 4 #include<ctime> 5 #include<iostream> 6 #include<algorithm> 7 #include<queue> 8 #include<stack> 9 #include<set> 10 #define esp (1e-6) 11 #defin

Tarjan强联通分量【模板】

1 #include <algorithm> 2 #include <cstdio> 3 4 using namespace std; 5 6 const int N(100015); 7 int n,m,v,u; 8 int edgesum,head[N]; 9 10 struct Edge 11 { 12 int from,to,next; 13 Edge(int from=0,int to=0,int next=0) : 14 from(from),to(to),next(n

习题:codevs 2822 爱在心中 解题报告

这次的解题报告是有关tarjan算法的一道思维量比较大的题目(真的是原创文章,希望管理员不要再把文章移出首页). 这道题蒟蒻以前做过,但是今天由于要复习tarjan算法,于是就看到codevs分类强联通分量里面只有这一道题. 题目是这样的: “每个人都拥有一个梦,即使彼此不相同,能够与你分享,无论失败成功都会感动.爱因为在心中,平凡而不平庸,世界就像迷宫,却又让我们此刻相逢Our Home.” 在爱的国度里有N个人,在他们的心中都有着一个爱的名单,上面记载着他所爱的人(不会出现自爱的情况).爱是

tarjan算法求强联通分量

昨天学到了一个新的算法tarjan算法,感觉最近都没有怎么学习了...(最近有个感悟啊,就是学习一定的通过实践来进步的. 现在才明白为什么高中的时候老师强调一定要刷题,当然刷完题目之后的总结也非常地重要! 这个tarjan算法用来求强联通分量,在网上看了几篇blog,然后做了一个题目,感觉这个算法很nice啊... 如果没有学这个算法, 我肯定会想直接dfs吧orz... dfs看看是不是每个点能到达连通分量的其他点,好像这样非常麻烦啊,还要记录这个点从哪里来的...这样一想,好像直接dfs我做

Tarjan的强联通分量

求强联通分量有很多种. <C++信息学奥赛一本通>  中讲过一个dfs求强联通分量的算法Kosdaraju,为了骗字数我就待会简单的说说.然而我们这篇文章的主体是Tarjan,所以我肯定说完之后再赞扬一下Tarjan大法好是不是 首先我们讲一下强联通分量 强联通分量指的是图的一个子图.在这个子图中,任意两个节点都可以互相到达.从定义上我们就可以看出是一个有向图来,因为任意一个无向图都符合该定义. 而它的标准定义是:有向图中任意两点都联通的最大子图. 咳咳,首先庆祝一下哈--本人博客的第一张图.

HDU 1269 迷宫城堡 (强联通分量,Tarjan算法)

Problem Description: 为了训练小希的方向感,Gardon建立了一座大城堡,里面有N个房间(N<=10000)和M条通道(M<=100000),每个通道都是单向的,就是说若称某通道连通了A房间和B房间,只说明可以通过这个通道由A房间到达B房间,但并不说明通过它可以由B房间到达A房间.Gardon需要请你写个程序确认一下是否任意两个房间都是相互连通的,即:对于任意的i和j,至少存在一条路径可以从房间i到房间j,也存在一条路径可以从房间j到房间i. Input: 输入包含多组数据

bzoj 2438: [中山市选2011]杀人游戏 (强联通分量 Tarjan)

Description 一位冷血的杀手潜入 Na-wiat,并假装成平民.警察希望能在 N 个人里面,查出谁是杀手. 警察能够对每一个人进行查证,假如查证的对象是平民,他会告诉警察,他认识的人, 谁是杀手, 谁是平民. 假如查证的对象是杀手, 杀手将会把警察干掉. 现在警察掌握了每一个人认识谁. 每一个人都有可能是杀手,可看作他们是杀手的概率是相同的. 问:根据最优的情况,保证警察自身安全并知道谁是杀手的概率最大是多少? Input 第一行有两个整数 N,M. 接下来有 M 行,每行两个整数 x

USACO06JAN The Cow Prom /// tarjan求强联通分量 oj24219

题目大意: n个点 m条边的图 求大小大于1的强联通分量的个数 https://www.cnblogs.com/stxy-ferryman/p/7779347.html tarjan求完强联通分量并染色后 计算一下每种颜色的个数 就是每个强联通块的大小 #include <stdio.h> #include <cstring> #include <algorithm> #include <stack> using namespace std; const i