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值,但是
这个强连通分量中的每一个点都要设成一样的)
  接着我们画画图:
codevs & vijos 爱在心中 - Tarjan

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

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

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

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

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

codevs & vijos 爱在心中 - Tarjan

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

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

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

Code:

 /*
*codevs.cn &Vijos.org
*Problem#2822 & Problem#1626
*Accepted & Accepted
*Time:2ms & 0ms
*Memory:256k & 584k
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<stack>
#define _min(a,b) ((a)<(b))?(a):(b)
using namespace std;
typedef bool boolean;
typedef class Edge{
public:
int end;
int next;
Edge():end(),next(){}
Edge(int end,int next):end(end),next(next){}
}Edge;
Edge *edge;
int n,m;
int *head;
int top;
inline void addEdge(int from,int end){
top++;
edge[top].next=head[from];
edge[top].end=end;
head[from]=top;
}
//Tanjan算法,变量
boolean *visited;
boolean *isCir;
int *visitID;
int *exitID;
int entryed;
stack<int> sta;
int *belong;
boolean *inStack;
int _count;
void getSonMap(int end){
int now=-;
int exits=;
while(now!=end){
now=sta.top();
belong[now]=end;
inStack[now]=false;
exits++;
sta.pop();
}
if(exits>){
_count++;
isCir[now]=true;
}
}
void Tarjan(const int pi){
int index=head[pi];
visitID[pi]=++entryed;
exitID[pi]=visitID[pi];
visited[pi]=true;
inStack[pi]=true;
sta.push(pi);
while(index!=){
if(!visited[edge[index].end]){
Tarjan(edge[index].end);
exitID[pi]=_min(exitID[pi],exitID[edge[index].end]);
}else if(inStack[edge[index].end]){
exitID[pi]=_min(exitID[pi],visitID[edge[index].end]);
}
index=edge[index].next;
}
if(exitID[pi]==visitID[pi]){
getSonMap(pi);
}
}
int *outgoing;
void rebuild(){
for(int i=;i<=n;i++){
for(int j=head[i];j!=;j=edge[j].next){
if(belong[edge[j].end]!=belong[i])
outgoing[belong[i]]++;
}
}
int result = ;
int id;
for(int i=;i<=n;i++){
if(outgoing[i]==&&isCir[i]){
result++;
id=belong[i];
}
}
if(result==){
for(int i=;i<=n;i++){
if(belong[i]==id){
printf("%d ",i);
}
}
}else{
printf("-1");
}
}
int main(){
cin>>n>>m;
head=new int[(const int)(n+)];
edge=new Edge[(const int)(m+)];
visited=new boolean[(const int)(n+)];
visitID=new int[(const int)(n+)];
exitID=new int[(const int)(n+)];
belong=new int[(const int)(n+)];
inStack=new boolean[(const int)(n+)];
isCir=new boolean[(const int)(n+)];
memset(head,,sizeof(int)*(n+));
memset(visited,false,sizeof(boolean)*(n+));
memset(inStack,false,sizeof(boolean)*(n+));
memset(isCir,false,sizeof(boolean)*(n+));
for(int i=;i<=m;i++){
int f,e;
scanf("%d%d",&f,&e);
addEdge(f,e);
}
for(int i=;i<=n;i++) belong[i]=i;
for(int i=;i<=n;i++){
if(!visited[i])
Tarjan(i);
}
cout<<_count<<endl;
delete[] visited;
delete[] inStack;
// visited=new boolean[(const int)(n+1)];
// inStack=new boolean[(const int)(n+1)];
// memset(visited,false,sizeof(boolean)*(n+1));
// memset(inStack,false,sizeof(boolean)*(n+1));
outgoing=new int[(const int)(n+)];
memset(outgoing,,sizeof(int)*(n+));
rebuild();
return ;
}

  

上一篇:关于c#静态构造函数


下一篇:.Net逆向初学习