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
限制
各个测试点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 )
这题虽然看起来很高大上的样子但是只要想通了就不怎么难了
很明显第二问要求的点是强连通分量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 }