给出一个无向图G的顶点V和边E。进行Q次查询,查询从G的某个顶点V[s]到另一个顶点V[t],是否存在2条不相交的路径。(两条路径不经过相同的边)
(注,无向图中不存在重边,也就是说确定起点和终点,他们之间最多只有1条路)
Input
第1行:2个数M N,中间用空格分开,M是顶点的数量,N是边的数量。(2 <= M <= 25000, 1 <= N <= 50000)
第2 - N + 1行,每行2个数,中间用空格分隔,分别是N条边的起点和终点的编号。例如2 4表示起点为2,终点为4,由于是无向图,所以从4到2也是可行的路径。
第N + 2行,一个数Q,表示后面将进行Q次查询。(1 <= Q <= 50000)
第N + 3 - N + 2 + Q行,每行2个数s, t,中间用空格分隔,表示查询的起点和终点。
Output
共Q行,如果从s到t存在2条不相交的路径则输出Yes,否则输出No。
Input示例
4 4
1 2
2 3
1 3
1 4
5
1 2
2 3
3 1
2 4
1 4
Output示例
Yes
Yes
Yes
No
No
Analysis
第一次知道原来边双联通分量的求法和强联通分量求法几乎一样...
只不过在无向图中的边双就没有 “在栈中” 的概念了,而是要保证不会走到自己父亲那里
= = 模拟一下发现确实两种要求的tarjan代码是一模一样的
= =
Code
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<stdio.h>
2 #include<iostream>
3 #define maxn 1000000
4 using namespace std;
5
6 int dfn[maxn],low[maxn],TIM,COL,color[maxn],n,m,q;
7 bool iscut[2*maxn],buck[maxn*2];
8
9 struct edge{ int from,u,v,bri; }e[maxn*2];
10 int tot,first[maxn]; void insert(int u,int v){
11 tot++; e[tot].bri = 0; e[tot].u = u; e[tot].from = first[u]; e[tot].v = v; first[u] = tot;
12 }
13
14 void dfs(int u,int fa){ // To tag the bri
15 dfn[u] = low[u] = ++TIM;
16 int child = 0;
17 for(int i = first[u];i;i = e[i].from){
18 int v = e[i].v; //if(v == fa) continue;
19 if(v != fa) child++;
20 if(!dfn[v]){
21 dfs(v,u);
22 low[u] = min(low[u],low[v]);
23 if(low[v] >= dfn[u]) iscut[u] = true;
24 }else if(dfn[v] < dfn[u] && v != fa) low[u] = min(low[u],dfn[v]);
25 }if(fa == u && child > 1) iscut[u] = false;
26 // printf("#%d: child %d iscut %d
",u,child,iscut[u]);
27 }
28
29 void tagg(){
30 for(int i = 1;i <= tot;i++)
31 if(iscut[e[i].u] && iscut[e[i].v])
32 e[i].bri = 1, buck[i] = true;
33 }
34
35 void dfs1(int u,int fa){
36 color[u] = COL;
37 for(int i = first[u];i;i = e[i].from){
38 if(e[i].v == fa || buck[i] || color[e[i].v]) continue;
39 dfs1(e[i].v,u);
40 }
41 }
42
43 int main(){
44 // freopen("16.txt","r",stdin);
45 // freopen("16.out","w",stdout);
46
47 scanf("%d%d",&n,&m);
48
49 for(int i = 1;i <= m;i++){
50 int u,v; scanf("%d%d",&u,&v);
51 insert(u,v); insert(v,u);
52 }for(int i=1;i<=n;i++)if(!dfn[i])
53 dfs(i,i); for(int i = 1;i <= n;i++)
54 if(!e[first[i]].from) iscut[i] = true;
55 // for(int i = 1;i <= n;i++) printf("%d ",iscut[i]); cout << endl;
56 tagg();
57
58 // for(int i = 1;i <= tot;i++) printf("#%d:%d->%d $%d$
",i,e[i].u,e[i].v,buck[i]);
59 // for(int i = 1;i <= n;i++) printf("%d ",color[i]); cout << endl;
60
61 for(int i = 1;i <= n;i++)
62 if(!color[i]){ ++COL; dfs1(i,i); }
63
64 scanf("%d",&q);
65
66 for(int i = 1;i <= q;i++){
67 int u,v; scanf("%d%d",&u,&v);
68 if(color[u] == color[v]) printf("Yes
");
69 else printf("No
");
70 }
71
72 return 0;
73 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<stdio.h>
2 #include<iostream>
3 #define maxn 2000000
4 using namespace std;
5
6 int dfn[maxn],low[maxn],TIM,s[maxn],poi,color[maxn],COL,n,m,q;
7
8 struct edge{ int from, u, v; }e[maxn];
9 int tot,first[maxn]; void insert(int u,int v){
10 tot++; e[tot].from = first[u]; e[tot].v = v; e[tot].u = u; first[u] = tot;
11 }
12
13 void dfs(int u,int fa){
14 // printf("Now deep in #%d
",u);
15 dfn[u] = low[u] = ++TIM;
16 s[poi++] = u;
17 for(int i = first[u];i;i = e[i].from){
18 int v = e[i].v; if(!dfn[v]){
19 // printf("#%d; get in Poi B
",u);
20 dfs(v,u); low[u] = min(low[u],low[v]);
21 }else if(dfn[v] < dfn[u] && v != fa) low[u] = min(low[u],dfn[v]);
22 }//printf("#%d: get in poi A
",u);
23
24 if(low[u] == dfn[u]){
25 // printf("#%d get the first!
",u);
26 color[u] = ++COL;
27 while(s[poi-1] != u && poi){
28 poi--; color[s[poi]] = COL;
29 }if(poi) poi--;
30 }
31 }
32
33 int main(){
34 scanf("%d%d",&n,&m);
35
36 for(int i = 1;i <= m;i++){
37 int u,v; scanf("%d%d",&u,&v);
38 insert(u,v); insert(v,u);
39 }for(int i = 1;i <= n;i++)
40 if(!color[i]) dfs(i,i);
41
42 // for(int i = 1;i <= n;i++) printf("%d ",color[i]); cout << endl;
43
44 scanf("%d",&q);
45
46 for(int i = 1;i <= q;i++){
47 int u,v; scanf("%d%d",&u,&v);
48 if(color[u] == color[v]) printf("Yes
");
49 else printf("No
");
50 }
51
52
53
54
55 return 0;
56 }