tarjan判环(51Nod - 1076)
模板
int DFN[maxn],low[maxn],cnt=0;
bool vis[maxn],inStack[maxn];///每次使用要清空
vector <int> edge[maxn];
stack <int> st;
void dfs(int u,int pre)///该例为无向图,pre保证没有n为2的环,可初始化为-1
{
vis[u]=1;
DFN[u]=low[u]=++cnt;
st.push(u);
inStack[u]=1;
int minn=DFN[u];
if(edge[u].size()>0)
{
for(int i=0;i<edge[u].size();i++)
{
int v=edge[u][i];
if(v==pre) continue;
if(!vis[v])
{
dfs(v,u);
}
if(inStack[v])
minn=min(low[v],minn);
}
}
low[u]=minn;
if(low[u]==DFN[u])
{
while(1)
{
int x=st.top();
st.pop();
inStack[x]=0;
low[x]=DFN[u];
if(x==u) break;
}
}
}
给出一个无向图G的顶点V和边E。进行Q次查询,查询从G的某个顶点Vs到另一个顶点Vt,是否存在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。
Sample Input
4 4
1 2
2 3
1 3
1 4
5
1 2
2 3
3 1
2 4
1 4
Sample Output
Yes
Yes
Yes
No
No
AC代码
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cctype>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<vector>
#include<algorithm>
using namespace std;
#define LL long long
const int maxn=25000+7;
int DFN[maxn],low[maxn],cnt=0,vis[maxn];
vector <int> edge[maxn];
stack <int> st;
void dfs(int u,int pre)
{
vis[u]=1;
DFN[u]=low[u]=++cnt;
st.push(u);
int minn=DFN[u];
if(edge[u].size()>0)
{
for(int i=0;i<edge[u].size();i++)
{
int v=edge[u][i];
if(v==pre) continue;
if(!vis[v])
{
dfs(v,u);
}
minn=min(low[v],minn);
}
}
low[u]=minn;
if(low[u]==DFN[u])
{
while(1)
{
int x=st.top();
st.pop();
low[x]=DFN[u];
if(x==u) break;
}
}
}
int main()
{
int n,m,i,j,k,x,y;
scanf("%d%d",&n,&m);
for(i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
edge[x].push_back(y);
edge[y].push_back(x);
}
for(i=1;i<=n;i++)
{
if(!vis[i]) dfs(i,0);
}
int q;
scanf("%d",&q);
while(q--)
{
scanf("%d%d",&x,&y);
if(low[x]==low[y]) printf("Yes\n");
else printf("No\n");
}
return 0;
}