WHYZOJ-#64 上白泽慧音(tarjan求强连通分量)

Posted 可惜没如果=_=

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了WHYZOJ-#64 上白泽慧音(tarjan求强连通分量)相关的知识,希望对你有一定的参考价值。

【题目描述】:

在幻想乡,上白泽慧音是以知识渊博闻名的老师。春雪异变导致人间之里的很多道路都被大雪堵塞,使有的学生不能顺利地到达慧音所在的村庄。因此慧音决定换一个能够聚集最多人数的村庄作为新的教学地点。

人间之里由N个村庄(编号为1..N)和M条道路组成,道路分为两种一种为单向通行的,一种为双向通行的,分别用1和2来标记。

如果存在由村庄A到达村庄B的通路,那么我们认为可以从村庄A到达村庄B,记为(A,B)。当(A,B)和(B,A)同时满足时,我们认为A,B是绝对连通的,记为。绝对连通区域是指一个村庄的集合,在这个集合中任意两个村庄X,Y都满足。

现在你的任务是,找出最大的绝对连通区域,并将这个绝对连通区域的村庄按编号依次输出。若存在两个最大的,输出字典序最小的,比如当存在1,3,4和2,5,6这两个最大连通区域时,输出的是1,3,4。

【输入描述】:

第1行:两个正整数N,M

第2..M+1行:每行三个正整数a,b,t, t = 1表示存在从村庄a到b的单向道路,t = 2表示村庄a,b之间存在双向通行的道路。保证每条道路只出现一次。

【输出描述】:

第1行: 1个整数,表示最大的绝对连通区域包含的村庄个数。

第2行:若干个整数,依次输出最大的绝对连通区域所包含的村庄编号。

【样例输入】:

5 5
1 2 1
1 3 2
2 4 2
5 1 2
3 5 1

【样例输出】:

3
1 3 5

【时间限制、数据范围及描述】:

时间:1s 空间:128M

对于60%的数据:N <= 200且M <= 10,000

对于100%的数据:N <= 5,000且M <= 50,000

 

肫帮我发现了我写的tarjan一直存在的bug(最开始的好像没有,后来由于POJ的辣鸡数据,好好的板子就被我打歪了还不自知),第一个判断下一个节点是否访问的时候同时要判断是否在栈中

 1 #include <cstdio>
 2 #include <cmath>
 3 #include <cstring>
 4 #include <cstdlib>
 5 #include <queue>
 6 #include <stack>
 7 #include <vector>
 8 #include <iostream>
 9 #include "algorithm"
10 #define mem(a,b) memset(a,b,sizeof(a))
11 using namespace std;
12 typedef long long LL;
13 const int MAX1=5005;
14 const int MAX2=100005;
15 int n,m;
16 int head[MAX1],adj[MAX2],next[MAX2];
17 int tot,tx;
18 int low[MAX1],dfn[MAX1],sta[MAX1];
19 bool t[MAX1],tt[MAX1];
20 int ans[MAX1];
21 inline int read(){
22     int x=1,an=0;char c=getchar();
23     while (c<0 || c>9){if (c==-) x=-1;c=getchar();}
24     while (c>=0 && c<=9){an=an*10+c-0;c=getchar();}
25     return x*an;
26 }
27 void addedge(int u,int v){
28     tot++;
29     adj[tot]=v;
30     next[tot]=head[u];
31     head[u]=tot;
32 }
33 void init(){
34     int i,j;
35     n=read();m=read();
36     int x,y,z;
37     ans[0]=sta[0]=tot=tx=0;
38     mem(head,0),mem(t,false),mem(tt,false);
39     for (i=1;i<=m;i++){
40         x=read();y=read();z=read();
41         if (z==1) addedge(x,y);
42         if (z==2) addedge(x,y),addedge(y,x);
43     }
44 }
45 void tarjan(int x){
46     sta[++sta[0]]=x;
47     dfn[x]=low[x]=++tx;
48     tt[x]=t[x]=true;
49     int i,j;
50     for (i=head[x];i;i=next[i]){
51         if (t[adj[i]] && tt[adj[i]])
52             low[x]=min(low[x],dfn[adj[i]]);
53         else{
54             tarjan(adj[i]);
55             low[x]=min(low[x],low[adj[i]]);
56         }
57     }
58     if (low[x]>=dfn[x]){
59         int zt[MAX1];
60         zt[0]=0;
61         do{
62             tt[sta[sta[0]]]=false;
63             zt[++zt[0]]=sta[sta[0]];
64         }while (sta[sta[0]--]!=x);
65         if (zt[0]>ans[0])
66             for (i=0;i<=zt[0];i++) ans[i]=zt[i];
67         if (zt[0]==ans[0]){
68             bool flag=true;
69             sort(zt+1,zt+zt[0]+1);
70             for (i=1;i<=zt[0];i++){
71                 if (zt[i]>ans[i]){
72                     flag=false;
73                     break;
74                 }
75             }
76             if (flag)
77                 for (i=0;i<=zt[0];i++) ans[i]=zt[i];
78         }
79     }
80 }
81 int main(){
82     freopen ("classroom.in","r",stdin);
83     freopen ("classroom.out","w",stdout);
84     init();int i,j;
85     for (i=1;i<=n;i++){
86         if (!t[i])
87             tarjan(i);
88     }
89     sort(ans+1,ans+ans[0]+1);
90     printf("%d\n",ans[0]);
91     for (i=1;i<=ans[0];i++)
92         printf("%d ",ans[i]);
93     return 0;
94 }

 

以上是关于WHYZOJ-#64 上白泽慧音(tarjan求强连通分量)的主要内容,如果未能解决你的问题,请参考以下文章

P1726 上白泽慧音 tarjan 模板

P1726 上白泽慧音 - Tarjan

[洛谷1726]上白泽慧音

codevs 1332 上白泽慧音

P1726 上白泽慧音

上白泽慧音——原来Tarjan 适用混合图,原来String 排字典序的确坑(或者说我的脑袋太水?)