[vios1023]维多利亚的舞会3<强联通分量tarjan>

题目链接:https://vijos.org/p/1023

最近在练强联通分量,当然学的是tarjan算法

而这一道题虽然打着难度为3,且是tarjan算法的裸题出没在vijos里面

但其实并不是纯粹只需要tarjan求有几个强联通就可以过的(我以为这是所谓的裸题)

其实这题还需要对每一个强联通缩点,可能被所谓裸题误导的OIer们看不破这个

毕竟,这个样例数据也是坑啊,样例数据都可以说是无向图了,哪里还是什么有向图

所以样例数据不是万能的,但是没过样例数据是万万不能的

至于为什么缩点我们来想一想,这张图中,怎么才满足可以被通知到

是在一个强联通分量里面?还是有一条边相连?还是有别的人指向他?

当然可以想到是有人指向他,这样就可以排除求出强联通分量个数的方法。。

不过我们可以确认的是,在一个强联通分量的点,只需要一个点就可以把这个强联通分量通知完,然后我们就可以判断任意两个强联通分量有没有可能有联系,也就是刚刚提到的有没有指向这个强联通分量的其他分量,也就是有没有入度。如果有入度,我们就可以把这个强联通分量与另一个合并,也就是这两个分量只要一个人就可以通知完。由于在这里理解成强联通分量会有些麻烦,所以就是所谓的缩点,把这个强联通分量看成一个点再来找边和入度

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<cmath>
 5 #include<queue>
 6 #include<stack>
 7 #include<algorithm>
 8 #include<cstdlib>
 9 #define maxn 205
10 using namespace std;
11 
12 struct node{
13     int u,v,w,nxt;
14 }e[maxn*maxn];
15 
16 int head[maxn],dfn[maxn],low[maxn],belong[maxn];
17 int num,tot,n,m,k,ans,in[maxn],cnt;
18 stack<int >s;
19 
20 void adde(int u,int v){
21     e[++tot].u=u;
22     e[tot].v=v;
23     e[tot].nxt=head[u];
24     head[u]=tot;
25 }
26 
27 void tarjan(int u){
28     num++;
29     dfn[u]=low[u]=num;
30     s.push(u);
31     for(int i=head[u];i!=-1;i=e[i].nxt){
32         int v=e[i].v;
33         if(dfn[v]==0){
34             tarjan(v);
35             low[u]=min(low[u],low[v]);
36         }else{
37             if(!belong[v])low[u]=min(low[u],dfn[v]);
38         }
39     }
40     if(dfn[u]==low[u]){
41         ans++;
42         belong[u]=ans;
43         while(s.top()!=u){
44             belong[s.top()]=ans;
45             s.pop();    
46         }s.pop();
47     }
48 }
49 
50 int main(){
51     memset(head,-1,sizeof(head));
52     scanf("%d",&n);
53     for(int i=1;i<=n;i++){
54         int a;scanf("%d",&a);
55         while(a!=0){
56             adde(i,a);scanf("%d",&a);}
57     }
58     for(int i=1;i<=n;i++){
59         if(dfn[i]==0)tarjan(i);
60     }
61     for(int i=1;i<=tot;i++){
62         int u=e[i].u,v=e[i].v;
63         if(belong[u]!=belong[v]){
64             in[belong[v]]++;
65         }
66     }
67     for(int i=1;i<=ans;i++){
68         if(!in[i])cnt++;
69     }
70     printf("%d",cnt);
71 }
View Code

【总结】

样例数据是万能的,不能过于相信样例,但是样例错了那就肯定错了

 

 

(另外,之前看见有人说原本想并查集但是错了,我个人没有想通为何不能简单的用并查集来偷懒,希望大佬能指点我一番)

原文地址:https://www.cnblogs.com/Danzel-Aria233/p/7774694.html