codevs & vijos 爱在心中 - Tarjan

描述

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

在爱的国度里有N个人,在他们的心中都有着一个爱的名单,上面记载着他所爱的人(不会出现自爱的情况)。爱是具有传递性的,即如果A爱B,B爱C,则A也爱C。

如果有这样一部分人,他们彼此都相爱,则他们就超越了一切的限制,用集体的爱化身成为一个爱心天使。

现在,我们想知道在这个爱的国度里会出现多少爱心天使。而且,如果某个爱心天使被其他所有人或爱心天使所爱则请输出这个爱心天使是由哪些人构成的,否则输出-1。

格式

输入格式

第1行,两个数N、M,代表爱的国度里有N个人,爱的关系有M条。

第2到第M+1行,每行两个数A、B,代表A爱B。

输出格式

第1行,一个数,代表爱的国度里有多少爱心天使。

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

样例1

样例输入1

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

样例输出1[复制]

 
2
2 3

样例2

样例输入2

 
3 3
1 2
2 1
2 3

样例输出2

 
1
-1

限制

各个测试点1s

提示

对于40%的数据 N<=10 M<=100
对于80%的数据 N<=100 M<=1000
对于100%的数据 N<=1000 M<=10000

来源

Cai0715 原创
NOIP 2009·Dream Team 模拟赛 第一期 第四题

(转自 https://vijos.org/p/1626 )

 


  这题虽然看起来很高大上的样子但是只要想通了就不怎么难了
  第一问直接Tarjan不解释。。
  第二问嘛。。。首先要把每个强连通分量缩成一个点(理由往下看吧)
所谓的缩点并不是意味着要把图拿来重构,其实用个类似于集合类的思想就
行了,首先将belong数组设成belong[i] = i当i在某个强连通分量中就把belong[i]
设成强连通分量固定的一个值(就是这个强连通分量内的任意一点的belong值,但是
这个强连通分量中的每一个点都要设成一样的)
  接着我们画画图:

  很明显第二问要求的点是强连通分量4,它有什么样的特点呢?

出度为0。如果它的出度不是0会发生什么(其他强连通分量的出度都不为0)?

就会和其他强连通分量形成一个更大的强连通分量,如果存着这个的话,tarjan

算法会先就把它求出来,也就是说这种情况是不可能

  还有一种情况,就是图不连通:

  这时候可以发现出度为0的点有两个,但是我们该输出-1

于是我们得到出度为0的点只能有1个,否则输出-1,至于输出

成员嘛。。直接照着belong数组扫一道,就行了

Code:

  1 /*
  2  *codevs.cn &Vijos.org
  3  *Problem#2822 & Problem#1626
  4  *Accepted       & Accepted
  5  *Time:2ms     & 0ms
  6  *Memory:256k  & 584k
  7  */
  8 #include<iostream>
  9 #include<cstdio>
 10 #include<cstring>
 11 #include<stack>
 12 #define _min(a,b) ((a)<(b))?(a):(b)
 13 using namespace std;
 14 typedef bool boolean;
 15 typedef class Edge{
 16     public:
 17         int end;
 18         int next;
 19         Edge():end(0),next(0){}
 20         Edge(int end,int next):end(end),next(next){}
 21 }Edge;
 22 Edge *edge;
 23 int n,m;
 24 int *head;
 25 int top;
 26 inline void addEdge(int from,int end){
 27     top++;
 28     edge[top].next=head[from];
 29     edge[top].end=end;
 30     head[from]=top;
 31 }
 32 //Tanjan算法,变量
 33 boolean *visited;
 34 boolean *isCir;
 35 int *visitID;
 36 int *exitID;
 37 int entryed;
 38 stack<int> sta;
 39 int *belong;
 40 boolean *inStack;
 41 int _count;
 42 void getSonMap(int end){
 43     int now=-1;
 44     int exits=0;
 45     while(now!=end){
 46         now=sta.top();
 47         belong[now]=end;
 48         inStack[now]=false;
 49         exits++;
 50         sta.pop();
 51     }
 52     if(exits>1){
 53         _count++;
 54         isCir[now]=true;
 55     }
 56 }
 57 void Tarjan(const int pi){
 58     int index=head[pi];
 59     visitID[pi]=++entryed;
 60     exitID[pi]=visitID[pi];
 61     visited[pi]=true;
 62     inStack[pi]=true;
 63     sta.push(pi);
 64     while(index!=0){
 65         if(!visited[edge[index].end]){
 66             Tarjan(edge[index].end);
 67             exitID[pi]=_min(exitID[pi],exitID[edge[index].end]);
 68         }else if(inStack[edge[index].end]){
 69             exitID[pi]=_min(exitID[pi],visitID[edge[index].end]);
 70         }
 71         index=edge[index].next;
 72     }
 73     if(exitID[pi]==visitID[pi]){
 74         getSonMap(pi);
 75     }
 76 }
 77 int *outgoing;
 78 void rebuild(){
 79     for(int i=1;i<=n;i++){
 80         for(int j=head[i];j!=0;j=edge[j].next){
 81             if(belong[edge[j].end]!=belong[i])
 82                 outgoing[belong[i]]++;
 83         }
 84     }
 85     int result = 0;
 86     int id;
 87     for(int i=1;i<=n;i++){
 88         if(outgoing[i]==0&&isCir[i]){
 89             result++;
 90             id=belong[i];
 91         }
 92     }
 93     if(result==1){
 94         for(int i=1;i<=n;i++){
 95             if(belong[i]==id){
 96                 printf("%d ",i);
 97             }
 98         }
 99     }else{
100         printf("-1");
101     }
102 }
103 int main(){
104     cin>>n>>m;
105     head=new int[(const int)(n+1)];
106     edge=new Edge[(const int)(m+1)];
107     visited=new boolean[(const int)(n+1)];
108     visitID=new int[(const int)(n+1)];
109     exitID=new int[(const int)(n+1)];
110     belong=new int[(const int)(n+1)];
111     inStack=new boolean[(const int)(n+1)];
112     isCir=new boolean[(const int)(n+1)];
113     memset(head,0,sizeof(int)*(n+1));
114     memset(visited,false,sizeof(boolean)*(n+1));
115     memset(inStack,false,sizeof(boolean)*(n+1));
116     memset(isCir,false,sizeof(boolean)*(n+1));
117     for(int i=1;i<=m;i++){
118         int f,e;
119         scanf("%d%d",&f,&e);
120         addEdge(f,e);
121     }
122     for(int i=1;i<=n;i++) belong[i]=i;
123     for(int i=1;i<=n;i++){
124         if(!visited[i])
125             Tarjan(i);
126     }
127     cout<<_count<<endl;
128     delete[] visited;
129     delete[] inStack;
130 //    visited=new boolean[(const int)(n+1)];
131 //    inStack=new boolean[(const int)(n+1)];
132 //    memset(visited,false,sizeof(boolean)*(n+1));
133 //    memset(inStack,false,sizeof(boolean)*(n+1));
134     outgoing=new int[(const int)(n+1)];
135     memset(outgoing,0,sizeof(int)*(n+1));
136     rebuild();
137     return 0;
138 }

  

posted @ 2016-07-16 21:30  阿波罗2003  阅读(486)  评论(0编辑  收藏  举报