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

 

题意:

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;
}

 

根据提供的引用内容,Codeforces Round 511 (Div. 1)是一个比赛的名称。然而,引用内容中没有提供与这个比赛相关的具体信息或问题。因此,我无法回答关于Codeforces Round 511 (Div. 1)的问题。如果您有关于这个比赛的具体问题,请提供更多的信息,我将尽力回答。 #### 引用[.reference_title] - *1* [Codeforces Round 860 (Div. 2)题解](https://blog.csdn.net/qq_60653991/article/details/129802687)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Codeforces Round 867 (Div. 3)(A题到E题)](https://blog.csdn.net/wdgkd/article/details/130370975)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [Codeforces Round 872 (Div. 2)(前三道](https://blog.csdn.net/qq_68286180/article/details/130570952)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值