Tarjan求强连通分量的流程在这个博客讲的很清楚,再加上我也没理解透,这里就不写了。
缩点:将同一个连通块内的点视为同一个点。
扔一道模板题:codeVS2822爱在心中
第一问很显然就是求点数大于一的连通块的个数,跑一次tarjan;
第二问脑补一下发现,缩点后,若图中有且仅有一个点出度为0且为爱心天使,则该点为所求的特殊爱心天使;
因为当缩点之后,图中不存在环,若有且仅有一个爱心天使出度为0,那么其他点一定有通向该爱心天使的路径。
若有两个点出度为0,那么他们彼此不被对方所爱。
若没有点出度为0,则图中存在环,矛盾。
看起来似乎没什么问题,但是写出来第五个点挂掉了,代码查不出错,若有人看到这篇博客,希望在下方指出错误,谢谢。
1 #include<cstdio> 2 #include<stack> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 #include<iostream> 7 using namespace std; 8 9 struct edge{ 10 int to,next; 11 }; 12 13 int a[5000][5000],dfn[10000],low[10000],head[10000],i,j,n,m,x,y,tag,ans[10000]; 14 int ans1=0,head2[10000],out[10000]; 15 bool visited[10000],b[10000],lowb[10000]; 16 edge e[10000],e2[10000]; 17 stack<int> s; 18 19 void tarjan(int k){ 20 int i,v; 21 dfn[k]=low[k]=++tag; 22 b[k]=true; 23 s.push(k); 24 for(i=head[k];i!=-1;i=e[i].next){ 25 v=e[i].to; 26 if(!dfn[v]){ 27 tarjan(v); 28 low[k]=min(low[k],low[v]); 29 }else 30 if(b[v]) 31 low[k]=min(low[k],dfn[v]); 32 } 33 int tmp=0; 34 if(dfn[k]==low[k]){ 35 //++ans1; 36 do{ 37 v=s.top(); 38 s.pop(); 39 b[v]=false; 40 tmp++; 41 }while(v!=k); 42 if(tmp>=2)++ans1; 43 } 44 } 45 46 int ne=0; 47 void add(int a,int b){ 48 e[++ne].to=b; e[ne].next=head[a]; head[a]=ne; 49 } 50 51 void add2(int a,int b){ 52 e2[++ne].to=b; e2[ne].next=head2[a]; head2[a]=ne; 53 } 54 55 int main(){ 56 memset(head,-1,sizeof(head)); 57 memset(head2,-1,sizeof(head2)); 58 scanf("%d%d",&n,&m); 59 for(i=1;i<=m;i++){ 60 scanf("%d%d",&x,&y); 61 add(x,y); 62 } 63 tag=0; 64 memset(dfn,0,sizeof(dfn)); 65 for(i=1;i<=n;i++){ 66 if(!dfn[i])tarjan(i); 67 } 68 printf("%d ",ans1); 69 70 ne=0; 71 int n2=0; 72 73 for(i=1;i<=n;i++){ 74 if(!lowb[low[i]]){ 75 n2=max(n2,low[i]); 76 lowb[low[i]]=true;//记录缩点后图中节点的编号 77 } 78 a[low[i]][++a[low[i]][0]]=i; 79 for(j=head[i];j!=-1;j=e[j].next){ 80 int v=e[j].to; 81 if(low[i]!=low[v]) 82 add2(low[i],low[v]); 83 } 84 //缩点:将low[]值相等的点看做一个点 85 } 86 87 for(i=1;i<=n2;i++){ 88 if(!lowb[i])continue; 89 for(j=head2[i];j!=-1;j=e2[j].next) 90 out[i]++; 91 } 92 93 int sum=0; 94 for(i=1;i<=n2;i++){ 95 if(out[i]==0&&lowb[i]){ 96 sum++; 97 j=i; 98 }; 99 } 100 101 if(sum!=1||a[j][0]<=1){ 102 printf("%d ",-1); 103 return 0; 104 } 105 106 for(i=1;i<=a[j][0];i++) 107 ans[i]=a[j][i]; 108 109 sort(ans+1,ans+1+a[j][0]); 110 111 for(i=1;i<=a[j][0];i++) 112 printf("%d ",ans[i]); 113 114 printf(" "); 115 return 0; 116 }
16.11.18:换了一种写法A了,然而还是不知道原来的代码有什么问题;
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<cmath> 5 #include<stack> 6 using namespace std; 7 struct edge{int to,next;}e1[1000010],e2[1000010]; 8 int head1[600000],head2[600000],dfn[600000],low[600000],belong[600000],out[600000]; 9 bool instack[600000]; 10 stack<int> s; 11 int dep,ne1,ne2,ans1,n,m,co; 12 void add1(int a,int b){ 13 e1[++ne1].to=b;e1[ne1].next=head1[a];head1[a]=ne1; 14 } 15 void add2(int a,int b){ 16 e2[++ne2].to=b;e2[ne2].next=head2[a];head2[a]=ne2; 17 } 18 void tarjan(int k){ 19 dfn[k]=low[k]=++dep; 20 instack[k]=true; 21 s.push(k); 22 for(int i=head1[k];i!=-1;i=e1[i].next){ 23 int v=e1[i].to; 24 if(!dfn[v]){ 25 tarjan(v); 26 low[k]=min(low[k],low[v]); 27 } 28 else if(instack[v]) 29 low[k]=min(low[k],dfn[v]); 30 } 31 int t; 32 if(low[k]==dfn[k]){ 33 int tmp=0; 34 ++co; 35 do{ 36 t=s.top(); 37 s.pop(); 38 instack[t]=false; 39 belong[t]=co;//染色缩点 40 tmp++; 41 }while(t!=k); 42 if(tmp>1)++ans1; 43 } 44 } 45 46 int main(){ 47 memset(head1,-1,sizeof(head1)); 48 memset(head2,-1,sizeof(head2)); 49 int i,j,u,v; 50 scanf("%d%d",&n,&m); 51 for(i=1;i<=m;i++){ 52 scanf("%d%d",&u,&v); 53 add1(u,v); 54 } 55 for(i=1;i<=n;i++){ 56 if(!dfn[i])tarjan(i); 57 } 58 printf("%d ",ans1); 59 60 int sum=0,ang=0; 61 for(i=1;i<=n;i++){ 62 for(j=head1[i];j!=-1;j=e1[j].next){ 63 int v=e1[j].to; 64 if(belong[v]!=belong[i]){ 65 out[belong[i]]++;//若邻接的两点颜色不同,则出度加一。 66 } 67 } 68 } 69 for(i=1;i<=co;i++){ 70 if(out[i]==0){ 71 ang=i; 72 ++sum; 73 } 74 } 75 if(sum==1){ 76 int sum2=0; 77 for(i=1;i<=n;i++){ 78 if(belong[i]==ang)sum2++; 79 } 80 if(sum2>1){ 81 for(i=1;i<=n;i++){ 82 if(belong[i]==ang)printf("%d ",i); 83 } 84 printf(" "); 85 }else{printf("-1 ");return 0;} 86 return 0; 87 } 88 printf("-1 ");return 0; 89 }