双联通分量求简单环(Educational Codeforces Round 42: F. Simple Cycles Edges)

版权声明:本文为博主原创文章,你们可以随便转载 https://blog.csdn.net/Jaihk662/article/details/83659752

题意:

n个点m条边的无向图,问有哪些边在一个简单环上,按顺序输出这些边的编号

思路:

对于无向图求出每个双联通分量,对于每个双联通分量,如果点的个数==边的个数,那么这个双联通分量就是个简单环,输出这个双联通分量的所有边,否则不是

这道题如果直接搜割点是不对的,两个特殊样例如下:

  • 对于样例①:割点是1,2,3,这样子的话很有可能只会找到3个双联通分量(1-4-5,2-6-7,3-8-9-10)从而将边算少
  • 对于样例②:割点是3,6,但是边(3,5)和(5,6)有可能被割点从它所属的双联通分量中分离,从而将边算多

解决方法:

直接在求双联通分量时用栈维护当前的边即可,而不用求割点后DFS,具体过程看代码注释

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<map>
#include<string>
#include<math.h>
#include<queue>
#include<stack>
#include<iostream>
using namespace std;
#define LL long long
#define mod 1000000007
vector<int> G[200005], F[200005];
stack<int> st, temp;
int cnt, t, cut, low[200005], time[200005], ans[200005], vis[200005], to[200005];
void Trajan(int u, int p, int last)
{
	int i, v, flag, now;
	low[u] = time[u] = ++t;
	for(i=0;i<G[u].size();i++)
	{
		v = G[u][i];
		if(v==p)
			continue;
		//printf("%d %d\n", u, v);
		if(time[v]==0)
		{
			to[F[u][i]] = v;
			st.push(F[u][i]);
			Trajan(v, u, F[u][i]);
			low[u] = min(low[u], low[v]);
			if(time[u]==low[v])		//u点是割点
			{
				cut++, flag = 1;
				while(1)
				{
					now = st.top();
					st.pop();
					//printf("%d %d\n", u, now);
					temp.push(now);
					if(vis[to[now]]!=cut)		//对于当前双联通分量中的每一条边,它们一个方向上的终点应该没有重复
						vis[to[now]] = cut;
					else
						flag = 0;
					if(now==F[u][i])
						break;
				}
				while(temp.empty()==0)
				{
					if(flag)
						ans[++cnt] = temp.top();
					temp.pop();
				}
			}
		}
		else if(time[v]<time[u])
		{
			to[F[u][i]] = v;
			st.push(F[u][i]);
			low[u] = min(low[u], time[v]);
		}
	}
	if(st.empty()==0 && st.top()==last)		//当前边为桥
	{
		//printf("%d %d\n", u, last);
		printf("%d\n", last);
		st.pop();
	}
}
int main(void)
{
	int n, m, i, x, y;
	scanf("%d%d", &n, &m);
	for(i=1;i<=m;i++)
	{
		scanf("%d%d", &x, &y);
		G[x].push_back(y), F[x].push_back(i);
		G[y].push_back(x), F[y].push_back(i);
	}
	for(i=1;i<=n;i++)
	{
		if(time[i]==0)
			Trajan(i, 0, 0);
	}
	sort(ans+1, ans+cnt+1);
	printf("%d\n", cnt);
	for(i=1;i<=cnt;i++)
		printf("%d ", ans[i]);
	puts("");
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Jaihk662/article/details/83659752