Freda的迷宫
题解
我们要使u与v之间有且只有一条简单路径,就是让这两个点必须联通,而且路径上没有环。
那么,就成了找桥,因为要保证两端的简单路径有且只有一条,就必须在由桥连成的路径两端。
我们便先用tarjan把所有的桥给跑出来,将桥边记录下来。
再用并查集来维护连接。因为将桥挑出来后所有的桥一定会形成一片森林,只要不在这片森林的同一棵树上则一定不是有且只有一条简单路径。
具体实现过程就很简单了。
源码
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<map>
#include<set>
using namespace std;
#define MAXM 100005
#define MAXN 10005
typedef long long LL;
#define gc() getchar()
template<typename _T>
void read(_T &x){
_T f=1;x=0;char s=gc();
while(s>'9'||s<'0'){if(s=='-')f=-1;s=gc();}
while(s>='0'&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=gc();}
x*=f;
}
int from[MAXM<<1],to[MAXM<<1],nxt[MAXM<<1];
int head[MAXN],tot,cnt,fa[MAXN];
int dfn[MAXN],low[MAXN];
int n,m,q;
void addEdge(int u,int v){
from[++tot]=u;to[tot]=v;
nxt[tot]=head[u];head[u]=tot;
}
void makeSet(int x){
for(int i=1;i<=x;i++)fa[i]=i;
}
int findSet(int x){
if(x!=fa[x])fa[x]=findSet(fa[x]);
return fa[x];
}
void unionSet(int a,int b){
int u=findSet(a),v=findSet(b);
if(u!=v)fa[u]=v;
}
void tarjan(int u,int f){
dfn[u]=low[u]=++cnt;
for(int i=head[u];i;i=nxt[i]){
int v=to[i];//printf("%d-->%d\n",u,v);
if(v==f)continue;
if(!dfn[v]){
tarjan(v,u);low[u]=min(low[u],low[v]);
if(low[v]>dfn[u])unionSet(u,v);
}
else if(dfn[v]<dfn[u])
low[u]=min(low[u],dfn[v]);
}
//printf("%d:%d %d\n",u,dfn[u],low[u]);
}
signed main(){
read(n);read(m);read(q);
for(int i=1;i<=m;i++){
int x,y;read(x);read(y);
addEdge(x,y);addEdge(y,x);
}
makeSet(n);tarjan(1,0);
for(int i=1;i<=q;i++){
int u,v;read(u);read(v);
int uu=findSet(u),vv=findSet(v);
puts(uu==vv?"Y":"N");
}
return 0;
}